mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-24 15:03:46 +00:00
Merge branch 'trunk' into assoc-list-dict
This commit is contained in:
commit
1b1b63aad0
66 changed files with 2681 additions and 780 deletions
10
.github/workflows/nix_macos_apple_silicon.yml
vendored
10
.github/workflows/nix_macos_apple_silicon.yml
vendored
|
@ -19,5 +19,15 @@ jobs:
|
|||
with:
|
||||
clean: "true"
|
||||
|
||||
- name: check code style with clippy
|
||||
run: nix develop -c cargo clippy --workspace --tests -- --deny warnings
|
||||
|
||||
- name: check code style with clippy --release
|
||||
run: cargo clippy --workspace --tests --release -- --deny warnings
|
||||
|
||||
# this needs to be done after clippy because of code generation in wasi-libc-sys
|
||||
- name: check formatting with rustfmt
|
||||
run: nix develop -c cargo fmt --all -- --check
|
||||
|
||||
- name: execute tests with --release
|
||||
run: nix develop -c cargo test --locked --release
|
||||
|
|
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -3520,6 +3520,7 @@ dependencies = [
|
|||
name = "roc_derive_key"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"roc_can",
|
||||
"roc_collections",
|
||||
"roc_error_macros",
|
||||
"roc_module",
|
||||
|
@ -3714,7 +3715,8 @@ dependencies = [
|
|||
"bumpalo",
|
||||
"roc_can",
|
||||
"roc_collections",
|
||||
"roc_derive_key",
|
||||
"roc_derive",
|
||||
"roc_error_macros",
|
||||
"roc_module",
|
||||
"roc_solve",
|
||||
"roc_types",
|
||||
|
@ -3769,6 +3771,7 @@ dependencies = [
|
|||
"roc_collections",
|
||||
"roc_constrain",
|
||||
"roc_debug_flags",
|
||||
"roc_derive",
|
||||
"roc_derive_key",
|
||||
"roc_error_macros",
|
||||
"roc_late_solve",
|
||||
|
@ -3810,7 +3813,7 @@ dependencies = [
|
|||
"roc_can",
|
||||
"roc_collections",
|
||||
"roc_debug_flags",
|
||||
"roc_derive_key",
|
||||
"roc_derive",
|
||||
"roc_error_macros",
|
||||
"roc_exhaustive",
|
||||
"roc_late_solve",
|
||||
|
@ -3959,7 +3962,7 @@ dependencies = [
|
|||
"roc_can",
|
||||
"roc_collections",
|
||||
"roc_constrain",
|
||||
"roc_derive_key",
|
||||
"roc_derive",
|
||||
"roc_exhaustive",
|
||||
"roc_load",
|
||||
"roc_module",
|
||||
|
@ -3988,6 +3991,7 @@ dependencies = [
|
|||
"roc_can",
|
||||
"roc_collections",
|
||||
"roc_debug_flags",
|
||||
"roc_derive",
|
||||
"roc_derive_key",
|
||||
"roc_error_macros",
|
||||
"roc_exhaustive",
|
||||
|
|
25
Earthfile
25
Earthfile
|
@ -12,7 +12,7 @@ install-other-libs:
|
|||
RUN apt -y install libunwind-dev pkg-config libx11-dev zlib1g-dev
|
||||
RUN apt -y install unzip # for www/build.sh
|
||||
|
||||
install-zig-llvm-valgrind-clippy-rustfmt:
|
||||
install-zig-llvm-valgrind:
|
||||
FROM +install-other-libs
|
||||
# editor
|
||||
RUN apt -y install libxkbcommon-dev
|
||||
|
@ -35,10 +35,6 @@ install-zig-llvm-valgrind-clippy-rustfmt:
|
|||
ENV RUSTFLAGS="-C link-arg=-fuse-ld=lld -C target-cpu=native"
|
||||
# valgrind
|
||||
RUN apt -y install valgrind
|
||||
# clippy
|
||||
RUN rustup component add clippy
|
||||
# rustfmt
|
||||
RUN rustup component add rustfmt
|
||||
# wasm repl & tests
|
||||
RUN rustup target add wasm32-unknown-unknown wasm32-wasi
|
||||
RUN apt -y install libssl-dev
|
||||
|
@ -53,11 +49,11 @@ install-zig-llvm-valgrind-clippy-rustfmt:
|
|||
ENV CARGO_INCREMENTAL=0 # no need to recompile package when using new function
|
||||
|
||||
copy-dirs:
|
||||
FROM +install-zig-llvm-valgrind-clippy-rustfmt
|
||||
FROM +install-zig-llvm-valgrind
|
||||
COPY --dir crates examples Cargo.toml Cargo.lock version.txt www ./
|
||||
|
||||
test-zig:
|
||||
FROM +install-zig-llvm-valgrind-clippy-rustfmt
|
||||
FROM +install-zig-llvm-valgrind
|
||||
COPY --dir crates/compiler/builtins/bitcode ./
|
||||
RUN cd bitcode && ./run-tests.sh && ./run-wasm-tests.sh
|
||||
|
||||
|
@ -70,19 +66,6 @@ build-rust-test:
|
|||
RUN --mount=type=cache,target=$SCCACHE_DIR \
|
||||
cargo test --locked --release --features with_sound --workspace --no-run && sccache --show-stats
|
||||
|
||||
check-clippy:
|
||||
FROM +build-rust-test
|
||||
RUN cargo clippy -V
|
||||
RUN --mount=type=cache,target=$SCCACHE_DIR \
|
||||
cargo clippy --workspace --tests -- --deny warnings
|
||||
RUN --mount=type=cache,target=$SCCACHE_DIR \
|
||||
cargo clippy --workspace --tests --release -- --deny warnings
|
||||
|
||||
check-rustfmt:
|
||||
FROM +build-rust-test
|
||||
RUN cargo fmt --version
|
||||
RUN cargo fmt --all -- --check
|
||||
|
||||
check-typos:
|
||||
RUN cargo install typos-cli --version 1.0.11 # version set to prevent confusion if the version is updated automatically
|
||||
COPY --dir .github ci crates examples nightly_benches www *.md LEGAL_DETAILS flake.nix version.txt ./
|
||||
|
@ -132,8 +115,6 @@ verify-no-git-changes:
|
|||
|
||||
test-all:
|
||||
BUILD +test-zig
|
||||
BUILD +check-rustfmt
|
||||
BUILD +check-clippy
|
||||
BUILD +test-rust
|
||||
BUILD +verify-no-git-changes
|
||||
|
||||
|
|
|
@ -10,15 +10,6 @@ pub fn load_module(src_file: &Path, threading: Threading) -> LoadedModule {
|
|||
let loaded = roc_load::load_and_typecheck(
|
||||
&arena,
|
||||
src_file.to_path_buf(),
|
||||
src_file
|
||||
.parent()
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"src_file {:?} did not have a parent directory but I need to have one.",
|
||||
src_file
|
||||
)
|
||||
})
|
||||
.to_path_buf(),
|
||||
subs_by_module,
|
||||
TargetInfo::default_x86_64(),
|
||||
roc_reporting::report::RenderTarget::ColorTerminal,
|
||||
|
|
|
@ -266,6 +266,9 @@ fn add_type(target_info: TargetInfo, id: TypeId, types: &Types, impls: &mut Impl
|
|||
// This is recursively pointing to a type that should already have been added,
|
||||
// so no extra work needs to happen.
|
||||
}
|
||||
RocType::Function(_, _) => {
|
||||
// TODO actually bindgen functions!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -375,7 +378,7 @@ pub struct {name} {{
|
|||
|
||||
write!(buf, "{INDENT}{tag_name}: ").unwrap();
|
||||
|
||||
if payload_type.has_pointer(types) {
|
||||
if cannot_derive_copy(payload_type, types) {
|
||||
// types with pointers need ManuallyDrop
|
||||
// because rust unions don't (and can't)
|
||||
// know how to drop them automatically!
|
||||
|
@ -553,7 +556,7 @@ pub struct {name} {{
|
|||
|
||||
match recursiveness {
|
||||
Recursiveness::Recursive => {
|
||||
if payload_type.has_pointer(types) {
|
||||
if cannot_derive_copy(payload_type, types) {
|
||||
owned_get_payload = format!(
|
||||
r#"{{
|
||||
let ptr = (self.pointer as usize & !{bitmask}) as *mut {union_name};
|
||||
|
@ -590,7 +593,7 @@ pub struct {name} {{
|
|||
};
|
||||
}
|
||||
Recursiveness::NonRecursive => {
|
||||
if payload_type.has_pointer(types) {
|
||||
if cannot_derive_copy(payload_type, types) {
|
||||
owned_get_payload =
|
||||
format!("core::mem::ManuallyDrop::take(&mut self.{tag_name})");
|
||||
borrowed_get_payload = format!("&self.{tag_name}");
|
||||
|
@ -620,7 +623,7 @@ pub struct {name} {{
|
|||
owned_ret = "payload".to_string();
|
||||
borrowed_ret = format!("&{owned_ret}");
|
||||
payload_args = format!("arg: {owned_ret_type}");
|
||||
args_to_payload = if payload_type.has_pointer(types) {
|
||||
args_to_payload = if cannot_derive_copy(payload_type, types) {
|
||||
"core::mem::ManuallyDrop::new(arg)".to_string()
|
||||
} else {
|
||||
"arg".to_string()
|
||||
|
@ -648,6 +651,7 @@ pub struct {name} {{
|
|||
payload_args = answer.payload_args;
|
||||
args_to_payload = answer.args_to_payload;
|
||||
}
|
||||
RocType::Function(_, _) => todo!(),
|
||||
};
|
||||
|
||||
{
|
||||
|
@ -790,7 +794,7 @@ pub struct {name} {{
|
|||
&mut drop_payload,
|
||||
|tag_name, opt_payload_id| {
|
||||
match opt_payload_id {
|
||||
Some(payload_id) if types.get_type(payload_id).has_pointer(types) => {
|
||||
Some(payload_id) if cannot_derive_copy(types.get_type(payload_id), types) => {
|
||||
format!("unsafe {{ core::mem::ManuallyDrop::drop(&mut {actual_self_mut}.{tag_name}) }},",)
|
||||
}
|
||||
_ => {
|
||||
|
@ -845,7 +849,7 @@ pub struct {name} {{
|
|||
|
||||
// The PartialEq impl for the tag union
|
||||
{
|
||||
let opt_impl_prefix = if typ.has_float(types) {
|
||||
let opt_impl_prefix = if has_float(typ, types) {
|
||||
String::new()
|
||||
} else {
|
||||
format!("impl Eq for {name} {{}}\n\n")
|
||||
|
@ -966,7 +970,7 @@ pub struct {name} {{
|
|||
|
||||
// The Clone impl for the tag union
|
||||
{
|
||||
let opt_impl_prefix = if typ.has_pointer(types) {
|
||||
let opt_impl_prefix = if cannot_derive_copy(typ, types) {
|
||||
String::new()
|
||||
} else {
|
||||
format!("impl Copy for {name} {{}}\n\n")
|
||||
|
@ -1089,7 +1093,7 @@ pub struct {name} {{
|
|||
// (because otherwise we're using ManuallyDrop's Debug instance
|
||||
// rather than the Debug instance of the value it wraps).
|
||||
let payload_type = types.get_type(payload_id);
|
||||
let deref_str = if payload_type.has_pointer(types) {
|
||||
let deref_str = if cannot_derive_copy(payload_type, types) {
|
||||
"&*"
|
||||
} else {
|
||||
"&"
|
||||
|
@ -1120,6 +1124,7 @@ pub struct {name} {{
|
|||
|
||||
buf.join("\n")
|
||||
}
|
||||
RocType::Function(_, _) => todo!(),
|
||||
};
|
||||
|
||||
format!(
|
||||
|
@ -1286,6 +1291,7 @@ fn type_name(id: TypeId, types: &Types) -> String {
|
|||
| RocType::TagUnion(RocTagUnion::NullableUnwrapped { name, .. })
|
||||
| RocType::TagUnion(RocTagUnion::NonNullableUnwrapped { name, .. }) => name.clone(),
|
||||
RocType::RecursivePointer(content) => type_name(*content, types),
|
||||
RocType::Function(_, _) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1295,7 +1301,7 @@ fn type_name(id: TypeId, types: &Types) -> String {
|
|||
fn derive_str(typ: &RocType, types: &Types, include_debug: bool) -> String {
|
||||
let mut buf = "#[derive(Clone, ".to_string();
|
||||
|
||||
if !typ.has_pointer(types) {
|
||||
if !cannot_derive_copy(typ, types) {
|
||||
buf.push_str("Copy, ");
|
||||
}
|
||||
|
||||
|
@ -1303,11 +1309,11 @@ fn derive_str(typ: &RocType, types: &Types, include_debug: bool) -> String {
|
|||
buf.push_str("Debug, ");
|
||||
}
|
||||
|
||||
if !typ.has_enumeration(types) {
|
||||
if !cannot_derive_default(typ, types) {
|
||||
buf.push_str("Default, ");
|
||||
}
|
||||
|
||||
if !typ.has_float(types) {
|
||||
if !has_float(typ, types) {
|
||||
buf.push_str("Eq, Ord, Hash, ");
|
||||
}
|
||||
|
||||
|
@ -1335,13 +1341,13 @@ fn add_nullable_unwrapped(
|
|||
let discriminant_name = add_discriminant(name, target_info, tag_names, types, impls);
|
||||
let payload_type = types.get_type(non_null_payload);
|
||||
let payload_type_name = type_name(non_null_payload, types);
|
||||
let has_pointer = payload_type.has_pointer(types);
|
||||
let cannot_derive_copy = cannot_derive_copy(payload_type, types);
|
||||
|
||||
// The opaque struct for the tag union
|
||||
{
|
||||
// This struct needs its own Clone impl because it has
|
||||
// a refcount to bump
|
||||
let derive_extras = if types.get_type(id).has_float(types) {
|
||||
let derive_extras = if has_float(types.get_type(id), types) {
|
||||
""
|
||||
} else {
|
||||
", Eq, Ord, Hash"
|
||||
|
@ -1430,6 +1436,7 @@ pub struct {name} {{
|
|||
owned_ret_type = answer.owned_ret_type;
|
||||
borrowed_ret_type = answer.borrowed_ret_type;
|
||||
}
|
||||
RocType::Function(_, _) => todo!(),
|
||||
};
|
||||
|
||||
// Add a convenience constructor function for the tag with the payload, e.g.
|
||||
|
@ -1481,7 +1488,7 @@ pub struct {name} {{
|
|||
);
|
||||
|
||||
{
|
||||
let assign_payload = if has_pointer {
|
||||
let assign_payload = if cannot_derive_copy {
|
||||
"core::mem::ManuallyDrop::take(&mut *self.pointer)"
|
||||
} else {
|
||||
"*self.pointer"
|
||||
|
@ -1624,7 +1631,7 @@ pub struct {name} {{
|
|||
// The Debug impl for the tag union
|
||||
{
|
||||
let opt_impl = Some(format!("impl core::fmt::Debug for {name}"));
|
||||
let extra_deref = if has_pointer { "*" } else { "" };
|
||||
let extra_deref = if cannot_derive_copy { "*" } else { "" };
|
||||
|
||||
let fields_str = match payload_type {
|
||||
RocType::RocStr
|
||||
|
@ -1659,6 +1666,7 @@ pub struct {name} {{
|
|||
|
||||
buf.join(&format!("\n{INDENT}{INDENT}{INDENT}{INDENT}{INDENT}"))
|
||||
}
|
||||
RocType::Function(_, _) => todo!(),
|
||||
};
|
||||
|
||||
let body = format!(
|
||||
|
@ -1852,3 +1860,124 @@ fn tag_union_struct_help<'a, I: Iterator<Item = &'a (L, TypeId)>, L: Display + P
|
|||
borrowed_ret_type,
|
||||
}
|
||||
}
|
||||
|
||||
fn cannot_derive_default(roc_type: &RocType, types: &Types) -> bool {
|
||||
match roc_type {
|
||||
RocType::TagUnion { .. } | RocType::RecursivePointer { .. } | RocType::Function(_, _) => {
|
||||
true
|
||||
}
|
||||
RocType::RocStr | RocType::Bool | RocType::Num(_) => false,
|
||||
RocType::RocList(id) | RocType::RocSet(id) | RocType::RocBox(id) => {
|
||||
cannot_derive_default(types.get_type(*id), types)
|
||||
}
|
||||
RocType::RocDict(key_id, val_id) => {
|
||||
cannot_derive_default(types.get_type(*key_id), types)
|
||||
|| cannot_derive_default(types.get_type(*val_id), types)
|
||||
}
|
||||
RocType::Struct { fields, .. } => fields
|
||||
.iter()
|
||||
.any(|(_, type_id)| cannot_derive_default(types.get_type(*type_id), types)),
|
||||
RocType::TagUnionPayload { fields, .. } => fields
|
||||
.iter()
|
||||
.any(|(_, type_id)| cannot_derive_default(types.get_type(*type_id), types)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Useful when determining whether to derive Copy in a Rust type.
|
||||
fn cannot_derive_copy(roc_type: &RocType, types: &Types) -> bool {
|
||||
match roc_type {
|
||||
RocType::Bool
|
||||
| RocType::Num(_)
|
||||
| RocType::TagUnion(RocTagUnion::Enumeration { .. })
|
||||
| RocType::Function(_, _) => false,
|
||||
RocType::RocStr
|
||||
| RocType::RocList(_)
|
||||
| RocType::RocDict(_, _)
|
||||
| RocType::RocSet(_)
|
||||
| RocType::RocBox(_)
|
||||
| RocType::TagUnion(RocTagUnion::NonNullableUnwrapped { .. })
|
||||
| RocType::TagUnion(RocTagUnion::NullableUnwrapped { .. })
|
||||
| RocType::TagUnion(RocTagUnion::NullableWrapped { .. })
|
||||
| RocType::TagUnion(RocTagUnion::Recursive { .. })
|
||||
| RocType::RecursivePointer { .. } => true,
|
||||
RocType::TagUnion(RocTagUnion::NonRecursive { tags, .. }) => {
|
||||
tags.iter().any(|(_, payloads)| {
|
||||
payloads
|
||||
.iter()
|
||||
.any(|id| cannot_derive_copy(types.get_type(*id), types))
|
||||
})
|
||||
}
|
||||
RocType::Struct { fields, .. } => fields
|
||||
.iter()
|
||||
.any(|(_, type_id)| cannot_derive_copy(types.get_type(*type_id), types)),
|
||||
RocType::TagUnionPayload { fields, .. } => fields
|
||||
.iter()
|
||||
.any(|(_, type_id)| cannot_derive_copy(types.get_type(*type_id), types)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Useful when determining whether to derive Eq, Ord, and Hash in a Rust type.
|
||||
fn has_float(roc_type: &RocType, types: &Types) -> bool {
|
||||
has_float_help(roc_type, types, &[])
|
||||
}
|
||||
|
||||
fn has_float_help(roc_type: &RocType, types: &Types, do_not_recurse: &[TypeId]) -> bool {
|
||||
match roc_type {
|
||||
RocType::Num(num) => {
|
||||
use RocNum::*;
|
||||
|
||||
match num {
|
||||
F32 | F64 | F128 => true,
|
||||
I8 | U8 | I16 | U16 | I32 | U32 | I64 | U64 | I128 | U128 | Dec => false,
|
||||
}
|
||||
}
|
||||
RocType::RocStr
|
||||
| RocType::Bool
|
||||
| RocType::TagUnion(RocTagUnion::Enumeration { .. })
|
||||
| RocType::Function(_, _) => false,
|
||||
RocType::RocList(id) | RocType::RocSet(id) | RocType::RocBox(id) => {
|
||||
has_float_help(types.get_type(*id), types, do_not_recurse)
|
||||
}
|
||||
RocType::RocDict(key_id, val_id) => {
|
||||
has_float_help(types.get_type(*key_id), types, do_not_recurse)
|
||||
|| has_float_help(types.get_type(*val_id), types, do_not_recurse)
|
||||
}
|
||||
RocType::Struct { fields, .. } => fields
|
||||
.iter()
|
||||
.any(|(_, type_id)| has_float_help(types.get_type(*type_id), types, do_not_recurse)),
|
||||
RocType::TagUnionPayload { fields, .. } => fields
|
||||
.iter()
|
||||
.any(|(_, type_id)| has_float_help(types.get_type(*type_id), types, do_not_recurse)),
|
||||
RocType::TagUnion(RocTagUnion::Recursive { tags, .. })
|
||||
| RocType::TagUnion(RocTagUnion::NonRecursive { tags, .. }) => {
|
||||
tags.iter().any(|(_, payloads)| {
|
||||
payloads
|
||||
.iter()
|
||||
.any(|id| has_float_help(types.get_type(*id), types, do_not_recurse))
|
||||
})
|
||||
}
|
||||
RocType::TagUnion(RocTagUnion::NullableWrapped { non_null_tags, .. }) => {
|
||||
non_null_tags.iter().any(|(_, _, payloads)| {
|
||||
payloads
|
||||
.iter()
|
||||
.any(|id| has_float_help(types.get_type(*id), types, do_not_recurse))
|
||||
})
|
||||
}
|
||||
RocType::TagUnion(RocTagUnion::NullableUnwrapped {
|
||||
non_null_payload: content,
|
||||
..
|
||||
})
|
||||
| RocType::TagUnion(RocTagUnion::NonNullableUnwrapped { content, .. })
|
||||
| RocType::RecursivePointer(content) => {
|
||||
if do_not_recurse.contains(content) {
|
||||
false
|
||||
} else {
|
||||
let mut do_not_recurse: Vec<TypeId> = do_not_recurse.into();
|
||||
|
||||
do_not_recurse.push(*content);
|
||||
|
||||
has_float_help(types.get_type(*content), types, &do_not_recurse)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ use target_lexicon::Triple;
|
|||
|
||||
pub fn load_types(
|
||||
full_file_path: PathBuf,
|
||||
dir: PathBuf,
|
||||
threading: Threading,
|
||||
) -> Result<Vec<(Types, TargetInfo)>, io::Error> {
|
||||
let target_info = (&Triple::host()).into();
|
||||
|
@ -28,7 +27,6 @@ pub fn load_types(
|
|||
} = roc_load::load_and_typecheck(
|
||||
arena,
|
||||
full_file_path,
|
||||
dir,
|
||||
subs_by_module,
|
||||
target_info,
|
||||
RenderTarget::Generic,
|
||||
|
|
|
@ -33,7 +33,6 @@ enum OutputType {
|
|||
pub fn main() {
|
||||
let opts = Opts::parse();
|
||||
let input_path = opts.platform_module;
|
||||
let cwd = std::env::current_dir().unwrap();
|
||||
let output_path = opts.dest;
|
||||
let output_type = match output_path.extension().and_then(OsStr::to_str) {
|
||||
Some("rs") => OutputType::Rust,
|
||||
|
@ -56,7 +55,7 @@ pub fn main() {
|
|||
}
|
||||
};
|
||||
|
||||
match load_types(input_path.clone(), cwd, Threading::AllAvailable) {
|
||||
match load_types(input_path.clone(), Threading::AllAvailable) {
|
||||
Ok(types_and_targets) => {
|
||||
let mut file = File::create(output_path.clone()).unwrap_or_else(|err| {
|
||||
eprintln!(
|
||||
|
|
|
@ -156,6 +156,7 @@ pub enum RocType {
|
|||
/// this would be the field of Cons containing the (recursive) StrConsList type,
|
||||
/// and the TypeId is the TypeId of StrConsList itself.
|
||||
RecursivePointer(TypeId),
|
||||
Function(Vec<TypeId>, TypeId),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
|
||||
|
@ -202,136 +203,6 @@ impl RocNum {
|
|||
}
|
||||
}
|
||||
|
||||
impl RocType {
|
||||
/// Useful when determining whether to derive Copy in a Rust type.
|
||||
pub fn has_pointer(&self, types: &Types) -> bool {
|
||||
match self {
|
||||
RocType::Bool
|
||||
| RocType::Num(_)
|
||||
| RocType::TagUnion(RocTagUnion::Enumeration { .. }) => false,
|
||||
RocType::RocStr
|
||||
| RocType::RocList(_)
|
||||
| RocType::RocDict(_, _)
|
||||
| RocType::RocSet(_)
|
||||
| RocType::RocBox(_)
|
||||
| RocType::TagUnion(RocTagUnion::NonNullableUnwrapped { .. })
|
||||
| RocType::TagUnion(RocTagUnion::NullableUnwrapped { .. })
|
||||
| RocType::TagUnion(RocTagUnion::NullableWrapped { .. })
|
||||
| RocType::TagUnion(RocTagUnion::Recursive { .. })
|
||||
| RocType::RecursivePointer { .. } => true,
|
||||
RocType::TagUnion(RocTagUnion::NonRecursive { tags, .. }) => {
|
||||
tags.iter().any(|(_, payloads)| {
|
||||
payloads
|
||||
.iter()
|
||||
.any(|id| types.get_type(*id).has_pointer(types))
|
||||
})
|
||||
}
|
||||
RocType::Struct { fields, .. } => fields
|
||||
.iter()
|
||||
.any(|(_, type_id)| types.get_type(*type_id).has_pointer(types)),
|
||||
RocType::TagUnionPayload { fields, .. } => fields
|
||||
.iter()
|
||||
.any(|(_, type_id)| types.get_type(*type_id).has_pointer(types)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Useful when determining whether to derive Eq, Ord, and Hash in a Rust type.
|
||||
pub fn has_float(&self, types: &Types) -> bool {
|
||||
self.has_float_help(types, &[])
|
||||
}
|
||||
|
||||
fn has_float_help(&self, types: &Types, do_not_recurse: &[TypeId]) -> bool {
|
||||
match self {
|
||||
RocType::Num(num) => {
|
||||
use RocNum::*;
|
||||
|
||||
match num {
|
||||
F32 | F64 | F128 => true,
|
||||
I8 | U8 | I16 | U16 | I32 | U32 | I64 | U64 | I128 | U128 | Dec => false,
|
||||
}
|
||||
}
|
||||
RocType::RocStr
|
||||
| RocType::Bool
|
||||
| RocType::TagUnion(RocTagUnion::Enumeration { .. }) => false,
|
||||
RocType::RocList(id) | RocType::RocSet(id) | RocType::RocBox(id) => {
|
||||
types.get_type(*id).has_float_help(types, do_not_recurse)
|
||||
}
|
||||
RocType::RocDict(key_id, val_id) => {
|
||||
types
|
||||
.get_type(*key_id)
|
||||
.has_float_help(types, do_not_recurse)
|
||||
|| types
|
||||
.get_type(*val_id)
|
||||
.has_float_help(types, do_not_recurse)
|
||||
}
|
||||
RocType::Struct { fields, .. } => fields.iter().any(|(_, type_id)| {
|
||||
types
|
||||
.get_type(*type_id)
|
||||
.has_float_help(types, do_not_recurse)
|
||||
}),
|
||||
RocType::TagUnionPayload { fields, .. } => fields.iter().any(|(_, type_id)| {
|
||||
types
|
||||
.get_type(*type_id)
|
||||
.has_float_help(types, do_not_recurse)
|
||||
}),
|
||||
RocType::TagUnion(RocTagUnion::Recursive { tags, .. })
|
||||
| RocType::TagUnion(RocTagUnion::NonRecursive { tags, .. }) => {
|
||||
tags.iter().any(|(_, payloads)| {
|
||||
payloads
|
||||
.iter()
|
||||
.any(|id| types.get_type(*id).has_float_help(types, do_not_recurse))
|
||||
})
|
||||
}
|
||||
RocType::TagUnion(RocTagUnion::NullableWrapped { non_null_tags, .. }) => {
|
||||
non_null_tags.iter().any(|(_, _, payloads)| {
|
||||
payloads
|
||||
.iter()
|
||||
.any(|id| types.get_type(*id).has_float_help(types, do_not_recurse))
|
||||
})
|
||||
}
|
||||
RocType::TagUnion(RocTagUnion::NullableUnwrapped {
|
||||
non_null_payload: content,
|
||||
..
|
||||
})
|
||||
| RocType::TagUnion(RocTagUnion::NonNullableUnwrapped { content, .. })
|
||||
| RocType::RecursivePointer(content) => {
|
||||
if do_not_recurse.contains(content) {
|
||||
false
|
||||
} else {
|
||||
let mut do_not_recurse: Vec<TypeId> = do_not_recurse.into();
|
||||
|
||||
do_not_recurse.push(*content);
|
||||
|
||||
types
|
||||
.get_type(*content)
|
||||
.has_float_help(types, &do_not_recurse)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Useful when determining whether to derive Default in a Rust type.
|
||||
pub fn has_enumeration(&self, types: &Types) -> bool {
|
||||
match self {
|
||||
RocType::TagUnion { .. } | RocType::RecursivePointer { .. } => true,
|
||||
RocType::RocStr | RocType::Bool | RocType::Num(_) => false,
|
||||
RocType::RocList(id) | RocType::RocSet(id) | RocType::RocBox(id) => {
|
||||
types.get_type(*id).has_enumeration(types)
|
||||
}
|
||||
RocType::RocDict(key_id, val_id) => {
|
||||
types.get_type(*key_id).has_enumeration(types)
|
||||
|| types.get_type(*val_id).has_enumeration(types)
|
||||
}
|
||||
RocType::Struct { fields, .. } => fields
|
||||
.iter()
|
||||
.any(|(_, type_id)| types.get_type(*type_id).has_enumeration(types)),
|
||||
RocType::TagUnionPayload { fields, .. } => fields
|
||||
.iter()
|
||||
.any(|(_, type_id)| types.get_type(*type_id).has_enumeration(types)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IntWidth> for RocNum {
|
||||
fn from(width: IntWidth) -> Self {
|
||||
match width {
|
||||
|
@ -558,8 +429,38 @@ fn add_type_help<'a>(
|
|||
}
|
||||
}
|
||||
},
|
||||
Content::Structure(FlatType::Func(_, _, _)) => {
|
||||
todo!()
|
||||
Content::Structure(FlatType::Func(args, _closure_var, ret_var)) => {
|
||||
let args = env.subs.get_subs_slice(*args);
|
||||
let mut arg_type_ids = Vec::with_capacity(args.len());
|
||||
|
||||
for arg_var in args {
|
||||
let arg_layout = env
|
||||
.layout_cache
|
||||
.from_var(env.arena, *arg_var, env.subs)
|
||||
.expect("Something weird ended up in the content");
|
||||
|
||||
arg_type_ids.push(add_type_help(env, arg_layout, *arg_var, None, types));
|
||||
}
|
||||
|
||||
let ret_type_id = {
|
||||
let ret_layout = env
|
||||
.layout_cache
|
||||
.from_var(env.arena, *ret_var, env.subs)
|
||||
.expect("Something weird ended up in the content");
|
||||
|
||||
add_type_help(env, ret_layout, *ret_var, None, types)
|
||||
};
|
||||
|
||||
let fn_type_id =
|
||||
types.add(RocType::Function(arg_type_ids.clone(), ret_type_id), layout);
|
||||
|
||||
types.depends(fn_type_id, ret_type_id);
|
||||
|
||||
for arg_type_id in arg_type_ids {
|
||||
types.depends(fn_type_id, arg_type_id);
|
||||
}
|
||||
|
||||
fn_type_id
|
||||
}
|
||||
Content::Structure(FlatType::FunctionOrTagUnion(_, _, _)) => {
|
||||
todo!()
|
||||
|
|
|
@ -33,7 +33,7 @@ pub fn generate_bindings(decl_src: &str) -> String {
|
|||
let mut file = File::create(file_path).unwrap();
|
||||
writeln!(file, "{}", &src).unwrap();
|
||||
|
||||
let result = load_types(full_file_path, dir.path().to_path_buf(), Threading::Single);
|
||||
let result = load_types(full_file_path, Threading::Single);
|
||||
|
||||
dir.close().expect("Unable to close tempdir");
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ pub struct BuiltFile {
|
|||
pub fn build_file<'a>(
|
||||
arena: &'a Bump,
|
||||
target: &Triple,
|
||||
src_dir: PathBuf,
|
||||
app_module_path: PathBuf,
|
||||
opt_level: OptLevel,
|
||||
emit_debug_info: bool,
|
||||
|
@ -55,7 +54,6 @@ pub fn build_file<'a>(
|
|||
let loaded = roc_load::load_and_monomorphize(
|
||||
arena,
|
||||
app_module_path.clone(),
|
||||
src_dir,
|
||||
subs_by_module,
|
||||
target_info,
|
||||
// TODO: expose this from CLI?
|
||||
|
@ -419,7 +417,6 @@ fn spawn_rebuild_thread(
|
|||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn check_file(
|
||||
arena: &Bump,
|
||||
src_dir: PathBuf,
|
||||
roc_file_path: PathBuf,
|
||||
emit_timings: bool,
|
||||
threading: Threading,
|
||||
|
@ -436,7 +433,6 @@ pub fn check_file(
|
|||
let mut loaded = roc_load::load_and_typecheck(
|
||||
arena,
|
||||
roc_file_path,
|
||||
src_dir,
|
||||
subs_by_module,
|
||||
target_info,
|
||||
// TODO: expose this from CLI?
|
||||
|
|
|
@ -353,8 +353,6 @@ pub fn test(matches: &ArgMatches, triple: Triple) -> io::Result<i32> {
|
|||
);
|
||||
}
|
||||
|
||||
let src_dir = path.parent().unwrap().canonicalize().unwrap();
|
||||
|
||||
// let target_valgrind = matches.is_present(FLAG_VALGRIND);
|
||||
|
||||
let arena = &arena;
|
||||
|
@ -368,7 +366,6 @@ pub fn test(matches: &ArgMatches, triple: Triple) -> io::Result<i32> {
|
|||
let loaded = roc_load::load_and_monomorphize(
|
||||
arena,
|
||||
path,
|
||||
src_dir,
|
||||
subs_by_module,
|
||||
target_info,
|
||||
// TODO: expose this from CLI?
|
||||
|
@ -494,12 +491,10 @@ pub fn build(
|
|||
}
|
||||
});
|
||||
|
||||
let src_dir = path.parent().unwrap().canonicalize().unwrap();
|
||||
let target_valgrind = matches.is_present(FLAG_VALGRIND);
|
||||
let res_binary_path = build_file(
|
||||
&arena,
|
||||
&triple,
|
||||
src_dir,
|
||||
path,
|
||||
opt_level,
|
||||
emit_debug_info,
|
||||
|
|
|
@ -90,8 +90,6 @@ fn main() -> io::Result<()> {
|
|||
let emit_timings = matches.is_present(FLAG_TIME);
|
||||
let filename = matches.value_of_os(ROC_FILE).unwrap();
|
||||
let roc_file_path = PathBuf::from(filename);
|
||||
let src_dir = roc_file_path.parent().unwrap().to_owned();
|
||||
|
||||
let threading = match matches
|
||||
.value_of(roc_cli::FLAG_MAX_THREADS)
|
||||
.and_then(|s| s.parse::<usize>().ok())
|
||||
|
@ -102,7 +100,7 @@ fn main() -> io::Result<()> {
|
|||
Some(n) => Threading::AtMost(n),
|
||||
};
|
||||
|
||||
match check_file(&arena, src_dir, roc_file_path, emit_timings, threading) {
|
||||
match check_file(&arena, roc_file_path, emit_timings, threading) {
|
||||
Ok((problems, total_time)) => {
|
||||
println!(
|
||||
"\x1B[{}m{}\x1B[39m {} and \x1B[{}m{}\x1B[39m {} found in {} ms.",
|
||||
|
|
|
@ -131,7 +131,7 @@ pub const RocDec = extern struct {
|
|||
return (c -% 48) <= 9;
|
||||
}
|
||||
|
||||
pub fn toStr(self: RocDec) ?RocStr {
|
||||
pub fn toStr(self: RocDec) RocStr {
|
||||
// Special case
|
||||
if (self.num == 0) {
|
||||
return RocStr.init("0.0", 3);
|
||||
|
@ -843,7 +843,7 @@ test "toStr: 123.45" {
|
|||
var res_roc_str = dec.toStr();
|
||||
|
||||
const res_slice: []const u8 = "123.45"[0..];
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.asSlice());
|
||||
}
|
||||
|
||||
test "toStr: -123.45" {
|
||||
|
@ -851,7 +851,7 @@ test "toStr: -123.45" {
|
|||
var res_roc_str = dec.toStr();
|
||||
|
||||
const res_slice: []const u8 = "-123.45"[0..];
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.asSlice());
|
||||
}
|
||||
|
||||
test "toStr: 123.0" {
|
||||
|
@ -859,7 +859,7 @@ test "toStr: 123.0" {
|
|||
var res_roc_str = dec.toStr();
|
||||
|
||||
const res_slice: []const u8 = "123.0"[0..];
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.asSlice());
|
||||
}
|
||||
|
||||
test "toStr: -123.0" {
|
||||
|
@ -867,7 +867,7 @@ test "toStr: -123.0" {
|
|||
var res_roc_str = dec.toStr();
|
||||
|
||||
const res_slice: []const u8 = "-123.0"[0..];
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.asSlice());
|
||||
}
|
||||
|
||||
test "toStr: 0.45" {
|
||||
|
@ -875,7 +875,7 @@ test "toStr: 0.45" {
|
|||
var res_roc_str = dec.toStr();
|
||||
|
||||
const res_slice: []const u8 = "0.45"[0..];
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.asSlice());
|
||||
}
|
||||
|
||||
test "toStr: -0.45" {
|
||||
|
@ -883,7 +883,7 @@ test "toStr: -0.45" {
|
|||
var res_roc_str = dec.toStr();
|
||||
|
||||
const res_slice: []const u8 = "-0.45"[0..];
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.asSlice());
|
||||
}
|
||||
|
||||
test "toStr: 0.00045" {
|
||||
|
@ -891,7 +891,7 @@ test "toStr: 0.00045" {
|
|||
var res_roc_str = dec.toStr();
|
||||
|
||||
const res_slice: []const u8 = "0.00045"[0..];
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.asSlice());
|
||||
}
|
||||
|
||||
test "toStr: -0.00045" {
|
||||
|
@ -899,7 +899,7 @@ test "toStr: -0.00045" {
|
|||
var res_roc_str = dec.toStr();
|
||||
|
||||
const res_slice: []const u8 = "-0.00045"[0..];
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.asSlice());
|
||||
}
|
||||
|
||||
test "toStr: -111.123456" {
|
||||
|
@ -907,7 +907,7 @@ test "toStr: -111.123456" {
|
|||
var res_roc_str = dec.toStr();
|
||||
|
||||
const res_slice: []const u8 = "-111.123456"[0..];
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.asSlice());
|
||||
}
|
||||
|
||||
test "toStr: 123.1111111" {
|
||||
|
@ -915,57 +915,57 @@ test "toStr: 123.1111111" {
|
|||
var res_roc_str = dec.toStr();
|
||||
|
||||
const res_slice: []const u8 = "123.1111111"[0..];
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.asSlice());
|
||||
}
|
||||
|
||||
test "toStr: 123.1111111111111 (big str)" {
|
||||
var dec: RocDec = .{ .num = 123111111111111000000 };
|
||||
var res_roc_str = dec.toStr();
|
||||
errdefer res_roc_str.?.deinit();
|
||||
defer res_roc_str.?.deinit();
|
||||
errdefer res_roc_str.deinit();
|
||||
defer res_roc_str.deinit();
|
||||
|
||||
const res_slice: []const u8 = "123.111111111111"[0..];
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.asSlice());
|
||||
}
|
||||
|
||||
test "toStr: 123.111111111111444444 (max number of decimal places)" {
|
||||
var dec: RocDec = .{ .num = 123111111111111444444 };
|
||||
var res_roc_str = dec.toStr();
|
||||
errdefer res_roc_str.?.deinit();
|
||||
defer res_roc_str.?.deinit();
|
||||
errdefer res_roc_str.deinit();
|
||||
defer res_roc_str.deinit();
|
||||
|
||||
const res_slice: []const u8 = "123.111111111111444444"[0..];
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.asSlice());
|
||||
}
|
||||
|
||||
test "toStr: 12345678912345678912.111111111111111111 (max number of digits)" {
|
||||
var dec: RocDec = .{ .num = 12345678912345678912111111111111111111 };
|
||||
var res_roc_str = dec.toStr();
|
||||
errdefer res_roc_str.?.deinit();
|
||||
defer res_roc_str.?.deinit();
|
||||
errdefer res_roc_str.deinit();
|
||||
defer res_roc_str.deinit();
|
||||
|
||||
const res_slice: []const u8 = "12345678912345678912.111111111111111111"[0..];
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.asSlice());
|
||||
}
|
||||
|
||||
test "toStr: std.math.maxInt" {
|
||||
var dec: RocDec = .{ .num = std.math.maxInt(i128) };
|
||||
var res_roc_str = dec.toStr();
|
||||
errdefer res_roc_str.?.deinit();
|
||||
defer res_roc_str.?.deinit();
|
||||
errdefer res_roc_str.deinit();
|
||||
defer res_roc_str.deinit();
|
||||
|
||||
const res_slice: []const u8 = "170141183460469231731.687303715884105727"[0..];
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.asSlice());
|
||||
}
|
||||
|
||||
test "toStr: std.math.minInt" {
|
||||
var dec: RocDec = .{ .num = std.math.minInt(i128) };
|
||||
var res_roc_str = dec.toStr();
|
||||
errdefer res_roc_str.?.deinit();
|
||||
defer res_roc_str.?.deinit();
|
||||
errdefer res_roc_str.deinit();
|
||||
defer res_roc_str.deinit();
|
||||
|
||||
const res_slice: []const u8 = "-170141183460469231731.687303715884105728"[0..];
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.asSlice());
|
||||
}
|
||||
|
||||
test "toStr: 0" {
|
||||
|
@ -973,7 +973,7 @@ test "toStr: 0" {
|
|||
var res_roc_str = dec.toStr();
|
||||
|
||||
const res_slice: []const u8 = "0.0"[0..];
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||
try expectEqualSlices(u8, res_slice, res_roc_str.asSlice());
|
||||
}
|
||||
|
||||
test "add: 0" {
|
||||
|
@ -1065,6 +1065,10 @@ pub fn fromStr(arg: RocStr) callconv(.C) num_.NumParseResult(i128) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn toStr(arg: RocDec) callconv(.C) RocStr {
|
||||
return @call(.{ .modifier = always_inline }, RocDec.toStr, .{arg});
|
||||
}
|
||||
|
||||
pub fn fromF64C(arg: f64) callconv(.C) i128 {
|
||||
return if (@call(.{ .modifier = always_inline }, RocDec.fromF64, .{arg})) |dec| dec.num else @panic("TODO runtime exception failing convert f64 to RocDec");
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ const dec = @import("dec.zig");
|
|||
|
||||
comptime {
|
||||
exportDecFn(dec.fromStr, "from_str");
|
||||
exportDecFn(dec.toStr, "to_str");
|
||||
exportDecFn(dec.fromF64C, "from_f64");
|
||||
exportDecFn(dec.eqC, "eq");
|
||||
exportDecFn(dec.neqC, "neq");
|
||||
|
@ -128,7 +129,6 @@ comptime {
|
|||
exportStrFn(str.strConcatC, "concat");
|
||||
exportStrFn(str.strJoinWithC, "joinWith");
|
||||
exportStrFn(str.strNumberOfBytes, "number_of_bytes");
|
||||
exportStrFn(str.strFromFloatC, "from_float");
|
||||
exportStrFn(str.strEqual, "equal");
|
||||
exportStrFn(str.substringUnsafe, "substring_unsafe");
|
||||
exportStrFn(str.getUnsafe, "get_unsafe");
|
||||
|
@ -149,6 +149,7 @@ comptime {
|
|||
}
|
||||
|
||||
inline for (FLOATS) |T| {
|
||||
str.exportFromFloat(T, ROC_BUILTINS ++ "." ++ STR ++ ".from_float.");
|
||||
num.exportParseFloat(T, ROC_BUILTINS ++ "." ++ STR ++ ".to_float.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -749,12 +749,18 @@ fn strFromIntHelp(comptime T: type, int: T) RocStr {
|
|||
}
|
||||
|
||||
// Str.fromFloat
|
||||
pub fn strFromFloatC(float: f64) callconv(.C) RocStr {
|
||||
return @call(.{ .modifier = always_inline }, strFromFloatHelp, .{ f64, float });
|
||||
pub fn exportFromFloat(comptime T: type, comptime name: []const u8) void {
|
||||
comptime var f = struct {
|
||||
fn func(float: T) callconv(.C) RocStr {
|
||||
return @call(.{ .modifier = always_inline }, strFromFloatHelp, .{ T, float });
|
||||
}
|
||||
}.func;
|
||||
|
||||
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||
}
|
||||
|
||||
fn strFromFloatHelp(comptime T: type, float: T) RocStr {
|
||||
var buf: [100]u8 = undefined;
|
||||
var buf: [400]u8 = undefined;
|
||||
const result = std.fmt.bufPrint(&buf, "{d}", .{float}) catch unreachable;
|
||||
|
||||
return RocStr.init(&buf, result.len);
|
||||
|
@ -1674,16 +1680,31 @@ pub fn fromUtf8Range(arg: RocList, start: usize, count: usize, update_mode: Upda
|
|||
.problem_code = Utf8ByteProblem.InvalidStartByte,
|
||||
};
|
||||
} else {
|
||||
// turn the bytes into a small string
|
||||
const string = RocStr.init(@ptrCast([*]const u8, bytes), count);
|
||||
|
||||
// decref the list
|
||||
utils.decref(arg.bytes, arg.len(), 1);
|
||||
|
||||
return FromUtf8Result{
|
||||
.is_ok = true,
|
||||
.string = RocStr.init(@ptrCast([*]const u8, bytes), count),
|
||||
.string = string,
|
||||
.byte_index = 0,
|
||||
.problem_code = Utf8ByteProblem.InvalidStartByte,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
const temp = errorToProblem(@ptrCast([*]u8, arg.bytes), arg.length);
|
||||
return FromUtf8Result{ .is_ok = false, .string = RocStr.empty(), .byte_index = temp.index, .problem_code = temp.problem };
|
||||
|
||||
// decref the list
|
||||
utils.decref(arg.bytes, arg.len(), 1);
|
||||
|
||||
return FromUtf8Result{
|
||||
.is_ok = false,
|
||||
.string = RocStr.empty(),
|
||||
.byte_index = temp.index,
|
||||
.problem_code = temp.problem,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -820,7 +820,10 @@ findIndex = \list, matcher ->
|
|||
## Some languages have a function called **`slice`** which works similarly to this.
|
||||
sublist : List elem, { start : Nat, len : Nat } -> List elem
|
||||
sublist = \list, config ->
|
||||
sublistLowlevel list config.start config.len
|
||||
if config.len == 0 then
|
||||
[]
|
||||
else
|
||||
sublistLowlevel list config.start config.len
|
||||
|
||||
## low-level slicing operation that does no bounds checking
|
||||
sublistLowlevel : List elem, Nat, Nat -> List elem
|
||||
|
|
|
@ -320,7 +320,7 @@ pub const STR_STARTS_WITH_SCALAR: &str = "roc_builtins.str.starts_with_scalar";
|
|||
pub const STR_ENDS_WITH: &str = "roc_builtins.str.ends_with";
|
||||
pub const STR_NUMBER_OF_BYTES: &str = "roc_builtins.str.number_of_bytes";
|
||||
pub const STR_FROM_INT: IntrinsicName = int_intrinsic!("roc_builtins.str.from_int");
|
||||
pub const STR_FROM_FLOAT: &str = "roc_builtins.str.from_float";
|
||||
pub const STR_FROM_FLOAT: IntrinsicName = float_intrinsic!("roc_builtins.str.from_float");
|
||||
pub const STR_TO_INT: IntrinsicName = int_intrinsic!("roc_builtins.str.to_int");
|
||||
pub const STR_TO_FLOAT: IntrinsicName = float_intrinsic!("roc_builtins.str.to_float");
|
||||
pub const STR_TO_DECIMAL: &str = "roc_builtins.str.to_decimal";
|
||||
|
@ -355,6 +355,7 @@ pub const LIST_APPEND_UNSAFE: &str = "roc_builtins.list.append_unsafe";
|
|||
pub const LIST_RESERVE: &str = "roc_builtins.list.reserve";
|
||||
|
||||
pub const DEC_FROM_STR: &str = "roc_builtins.dec.from_str";
|
||||
pub const DEC_TO_STR: &str = "roc_builtins.dec.to_str";
|
||||
pub const DEC_FROM_F64: &str = "roc_builtins.dec.from_f64";
|
||||
pub const DEC_EQ: &str = "roc_builtins.dec.eq";
|
||||
pub const DEC_NEQ: &str = "roc_builtins.dec.neq";
|
||||
|
|
|
@ -359,9 +359,6 @@ impl IAbilitiesStore<Resolved> {
|
|||
}
|
||||
|
||||
pub fn insert_resolved(&mut self, id: SpecializationId, specialization: Symbol) {
|
||||
// May not be a thing in mono
|
||||
// debug_assert!(self.is_specialization_name(specialization));
|
||||
|
||||
let old_specialization = self.resolved_specializations.insert(id, specialization);
|
||||
|
||||
debug_assert!(
|
||||
|
@ -371,15 +368,6 @@ impl IAbilitiesStore<Resolved> {
|
|||
);
|
||||
}
|
||||
|
||||
pub fn remove_resolved(&mut self, id: SpecializationId) {
|
||||
let old_specialization = self.resolved_specializations.remove(&id);
|
||||
|
||||
debug_assert!(
|
||||
old_specialization.is_some(),
|
||||
"Trying to remove a resolved specialization that was never there!",
|
||||
);
|
||||
}
|
||||
|
||||
pub fn get_resolved(&self, id: SpecializationId) -> Option<Symbol> {
|
||||
self.resolved_specializations.get(&id).copied()
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
use roc_can::{
|
||||
use crate::{
|
||||
def::Def,
|
||||
expr::{AccessorData, ClosureData, Expr, Field, OpaqueWrapFunctionData, WhenBranch},
|
||||
};
|
||||
use roc_module::ident::{Lowercase, TagName};
|
||||
use roc_module::{
|
||||
ident::{Lowercase, TagName},
|
||||
symbol::Symbol,
|
||||
};
|
||||
use roc_types::{
|
||||
subs::{
|
||||
self, AliasVariables, Descriptor, GetSubsSlice, OptVariable, RecordFields, Subs, SubsIndex,
|
||||
|
@ -62,6 +65,8 @@ trait CopyEnv {
|
|||
|
||||
fn clone_tag_names(&mut self, tag_names: SubsSlice<TagName>) -> SubsSlice<TagName>;
|
||||
|
||||
fn clone_lambda_names(&mut self, lambda_names: SubsSlice<Symbol>) -> SubsSlice<Symbol>;
|
||||
|
||||
fn clone_record_fields(
|
||||
&mut self,
|
||||
record_fields: SubsSlice<RecordField<()>>,
|
||||
|
@ -104,6 +109,11 @@ impl CopyEnv for Subs {
|
|||
tag_names
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn clone_lambda_names(&mut self, lambda_names: SubsSlice<Symbol>) -> SubsSlice<Symbol> {
|
||||
lambda_names
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn clone_record_fields(
|
||||
&mut self,
|
||||
|
@ -160,6 +170,14 @@ impl<'a> CopyEnv for AcrossSubs<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn clone_lambda_names(&mut self, lambda_names: SubsSlice<Symbol>) -> SubsSlice<Symbol> {
|
||||
SubsSlice::extend_new(
|
||||
&mut self.target.closure_names,
|
||||
self.source.get_subs_slice(lambda_names).iter().cloned(),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn clone_record_fields(
|
||||
&mut self,
|
||||
|
@ -186,9 +204,9 @@ pub fn deep_copy_expr_across_subs(
|
|||
target: &mut Subs,
|
||||
var: Variable,
|
||||
expr: &Expr,
|
||||
) -> Option<(Variable, Expr)> {
|
||||
) -> (Variable, Expr) {
|
||||
let mut across_subs = AcrossSubs { source, target };
|
||||
deep_copy_type_vars_into_expr_help(&mut across_subs, var, expr)
|
||||
deep_copy_type_vars_into_expr_help(&mut across_subs, var, expr).unwrap()
|
||||
}
|
||||
|
||||
/// Deep copies all type variables in [`expr`].
|
||||
|
@ -849,8 +867,10 @@ fn deep_copy_type_vars<C: CopyEnv>(
|
|||
env.target().variable_slices[target_index] = new_variables;
|
||||
}
|
||||
|
||||
let new_solved_labels = env.clone_lambda_names(solved.labels());
|
||||
|
||||
let new_solved =
|
||||
UnionLambdas::from_slices(solved.labels(), new_variable_slices);
|
||||
UnionLambdas::from_slices(new_solved_labels, new_variable_slices);
|
||||
|
||||
let new_unspecialized =
|
||||
SubsSlice::reserve_uls_slice(env.target(), unspecialized.len());
|
||||
|
@ -887,10 +907,12 @@ fn deep_copy_type_vars<C: CopyEnv>(
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::copy::{deep_copy_type_vars_into_expr, AcrossSubs};
|
||||
use crate::{
|
||||
copy::{deep_copy_type_vars_into_expr, AcrossSubs},
|
||||
expr::Expr,
|
||||
};
|
||||
|
||||
use super::{deep_copy_expr_across_subs, deep_copy_type_vars};
|
||||
use roc_can::expr::Expr;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::{ident::TagName, symbol::Symbol};
|
||||
use roc_region::all::Loc;
|
||||
|
@ -1105,8 +1127,7 @@ mod test {
|
|||
)],
|
||||
};
|
||||
|
||||
let (var, expr) =
|
||||
deep_copy_expr_across_subs(&mut source, &mut target, var1, &expr).unwrap();
|
||||
let (var, expr) = deep_copy_expr_across_subs(&mut source, &mut target, var1, &expr);
|
||||
|
||||
assert!(source.get_copy(var1).is_none());
|
||||
assert!(source.get_copy(var2).is_none());
|
|
@ -471,6 +471,15 @@ pub enum Recursive {
|
|||
TailRecursive = 2,
|
||||
}
|
||||
|
||||
impl Recursive {
|
||||
pub fn is_recursive(&self) -> bool {
|
||||
match self {
|
||||
Recursive::NotRecursive => false,
|
||||
Recursive::Recursive | Recursive::TailRecursive => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WhenBranch {
|
||||
pub patterns: Vec<Loc<Pattern>>,
|
||||
|
|
|
@ -5,6 +5,7 @@ pub mod abilities;
|
|||
pub mod annotation;
|
||||
pub mod builtins;
|
||||
pub mod constraint;
|
||||
pub mod copy;
|
||||
pub mod def;
|
||||
pub mod effect_module;
|
||||
pub mod env;
|
||||
|
|
|
@ -20,7 +20,7 @@ use roc_types::subs::{
|
|||
};
|
||||
use roc_types::types::{AliasKind, RecordField};
|
||||
|
||||
use crate::{synth_var, DerivedBody, DERIVED_MODULE};
|
||||
use crate::{synth_var, DerivedBody, DERIVED_SYNTH};
|
||||
|
||||
macro_rules! bad_input {
|
||||
($subs:expr, $var:expr) => {
|
||||
|
@ -64,7 +64,7 @@ impl Env<'_> {
|
|||
|
||||
let ident_id = self.derived_ident_ids.get_or_insert(&debug_name);
|
||||
|
||||
Symbol::new(DERIVED_MODULE, ident_id)
|
||||
Symbol::new(DERIVED_SYNTH, ident_id)
|
||||
} else {
|
||||
self.unique_symbol()
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ impl Env<'_> {
|
|||
|
||||
fn unique_symbol(&mut self) -> Symbol {
|
||||
let ident_id = self.derived_ident_ids.gen_unique();
|
||||
Symbol::new(DERIVED_MODULE, ident_id)
|
||||
Symbol::new(DERIVED_SYNTH, ident_id)
|
||||
}
|
||||
|
||||
fn import_encode_symbol(&mut self, symbol: Symbol) -> Variable {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
use std::iter::once;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use roc_can::abilities::SpecializationLambdaSets;
|
||||
use roc_can::expr::Expr;
|
||||
use roc_can::pattern::Pattern;
|
||||
use roc_can::{def::Def, module::ExposedByModule};
|
||||
|
@ -16,9 +17,7 @@ use roc_types::subs::{
|
|||
|
||||
mod encoding;
|
||||
|
||||
type SpecializationLambdaSets = VecMap<u8, Variable>;
|
||||
|
||||
pub(crate) const DERIVED_MODULE: ModuleId = ModuleId::DERIVED;
|
||||
pub(crate) const DERIVED_SYNTH: ModuleId = ModuleId::DERIVED_SYNTH;
|
||||
|
||||
pub fn synth_var(subs: &mut Subs, content: Content) -> Variable {
|
||||
let descriptor = Descriptor {
|
||||
|
@ -34,20 +33,13 @@ pub fn synth_var(subs: &mut Subs, content: Content) -> Variable {
|
|||
}
|
||||
|
||||
/// Map of [`DeriveKey`]s to their derived symbols.
|
||||
///
|
||||
/// This represents the [`Derived_synth`][Symbol::DERIVED_SYNTH] module.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct DerivedModule {
|
||||
map: MutMap<DeriveKey, (Symbol, Def, SpecializationLambdaSets)>,
|
||||
subs: Subs,
|
||||
derived_ident_ids: IdentIds,
|
||||
|
||||
/// Has someone stolen subs/ident ids from us?
|
||||
#[cfg(debug_assertions)]
|
||||
stolen: bool,
|
||||
}
|
||||
|
||||
pub struct StolenFromDerived {
|
||||
pub subs: Subs,
|
||||
pub ident_ids: IdentIds,
|
||||
}
|
||||
|
||||
pub(crate) struct DerivedBody {
|
||||
|
@ -98,51 +90,45 @@ impl DerivedModule {
|
|||
exposed_by_module: &ExposedByModule,
|
||||
key: DeriveKey,
|
||||
) -> &(Symbol, Def, SpecializationLambdaSets) {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
debug_assert!(!self.stolen, "attempting to add to stolen symbols!");
|
||||
match self.map.get(&key) {
|
||||
Some(entry) => {
|
||||
// rustc won't let us return an immutable reference *and* continue using
|
||||
// `self.map` immutably below, but this is safe, because we are not returning
|
||||
// an immutable reference to the entry.
|
||||
return unsafe { std::mem::transmute(entry) };
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
// TODO: can we get rid of the clone?
|
||||
let entry = self.map.entry(key.clone());
|
||||
let ident_id = if cfg!(debug_assertions) || cfg!(feature = "debug-derived-symbols") {
|
||||
let debug_name = key.debug_name();
|
||||
let ident_id = self.derived_ident_ids.get_or_insert(&debug_name);
|
||||
|
||||
entry.or_insert_with(|| {
|
||||
let ident_id = if cfg!(any(
|
||||
debug_assertions,
|
||||
test,
|
||||
feature = "debug-derived-symbols"
|
||||
)) {
|
||||
let debug_name = key.debug_name();
|
||||
debug_assert!(
|
||||
self.derived_ident_ids.get_id(&debug_name).is_none(),
|
||||
"duplicate debug name for different derive key"
|
||||
);
|
||||
self.derived_ident_ids.get_or_insert(&debug_name)
|
||||
} else {
|
||||
self.derived_ident_ids.gen_unique()
|
||||
};
|
||||
// This is expensive, but yields much better symbols when debugging.
|
||||
// TODO: hide behind debug_flags?
|
||||
DERIVED_SYNTH.register_debug_idents(&self.derived_ident_ids);
|
||||
|
||||
let derived_symbol = Symbol::new(DERIVED_MODULE, ident_id);
|
||||
let (derived_def, specialization_lsets) = build_derived_body(
|
||||
&mut self.subs,
|
||||
&mut self.derived_ident_ids,
|
||||
exposed_by_module,
|
||||
derived_symbol,
|
||||
key.clone(),
|
||||
);
|
||||
ident_id
|
||||
} else {
|
||||
self.derived_ident_ids.gen_unique()
|
||||
};
|
||||
|
||||
(derived_symbol, derived_def, specialization_lsets)
|
||||
})
|
||||
let derived_symbol = Symbol::new(DERIVED_SYNTH, ident_id);
|
||||
let (derived_def, specialization_lsets) = build_derived_body(
|
||||
&mut self.subs,
|
||||
&mut self.derived_ident_ids,
|
||||
exposed_by_module,
|
||||
derived_symbol,
|
||||
key.clone(),
|
||||
);
|
||||
|
||||
let triple = (derived_symbol, derived_def, specialization_lsets);
|
||||
self.map.entry(key).or_insert(triple)
|
||||
}
|
||||
|
||||
pub fn iter_all(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (&DeriveKey, &(Symbol, Def, SpecializationLambdaSets))> {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
debug_assert!(!self.stolen);
|
||||
}
|
||||
|
||||
self.map.iter()
|
||||
}
|
||||
|
||||
|
@ -150,57 +136,25 @@ impl DerivedModule {
|
|||
/// module; other modules should use [`Self::get_or_insert`] to generate a symbol for a derived
|
||||
/// ability member usage.
|
||||
pub fn gen_unique(&mut self) -> Symbol {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
debug_assert!(!self.stolen);
|
||||
}
|
||||
|
||||
let ident_id = self.derived_ident_ids.gen_unique();
|
||||
Symbol::new(DERIVED_MODULE, ident_id)
|
||||
Symbol::new(DERIVED_SYNTH, ident_id)
|
||||
}
|
||||
|
||||
/// Steal all created derived ident Ids.
|
||||
/// After this is called, [`Self::get_or_insert`] may no longer be called.
|
||||
pub fn steal(&mut self) -> StolenFromDerived {
|
||||
let mut ident_ids = Default::default();
|
||||
std::mem::swap(&mut self.derived_ident_ids, &mut ident_ids);
|
||||
let mut subs = Default::default();
|
||||
std::mem::swap(&mut self.subs, &mut subs);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
debug_assert!(!self.stolen);
|
||||
self.stolen = true;
|
||||
}
|
||||
|
||||
StolenFromDerived { subs, ident_ids }
|
||||
}
|
||||
|
||||
pub fn return_stolen(&mut self, stolen: StolenFromDerived) {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
debug_assert!(self.stolen);
|
||||
self.stolen = false;
|
||||
}
|
||||
|
||||
let StolenFromDerived { subs, ident_ids } = stolen;
|
||||
|
||||
self.subs = subs;
|
||||
self.derived_ident_ids = ident_ids;
|
||||
}
|
||||
|
||||
pub fn copy_lambda_set_var_to_subs(&self, var: Variable, target: &mut Subs) -> Variable {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
debug_assert!(!self.stolen);
|
||||
}
|
||||
// TODO: just pass and copy the ambient function directly, don't pass the lambda set var.
|
||||
pub fn copy_lambda_set_ambient_function_to_subs(
|
||||
&self,
|
||||
lambda_set_var: Variable,
|
||||
target: &mut Subs,
|
||||
_target_rank: Rank,
|
||||
) -> Variable {
|
||||
let ambient_function_var = self.subs.get_lambda_set(lambda_set_var).ambient_function;
|
||||
|
||||
let copied_import = copy_import_to(
|
||||
&self.subs,
|
||||
target,
|
||||
// bookkeep unspecialized lambda sets of var - I think don't want this here
|
||||
false,
|
||||
var,
|
||||
// bookkeep unspecialized lambda sets of var - I think we want this here
|
||||
true,
|
||||
ambient_function_var,
|
||||
// TODO: I think this is okay because the only use of `copy_lambda_set_var_to_subs`
|
||||
// (at least right now) is for lambda set compaction, which will automatically unify
|
||||
// and lower ranks, and never generalize.
|
||||
|
@ -208,11 +162,52 @@ impl DerivedModule {
|
|||
// However this is a bad coupling and maybe not a good assumption, we should revisit
|
||||
// this when possible.
|
||||
Rank::import(),
|
||||
// target_rank,
|
||||
);
|
||||
|
||||
copied_import.variable
|
||||
}
|
||||
|
||||
/// Gets the derived defs that should be loaded into the derived gen module, skipping over the
|
||||
/// defs that have already been loaded.
|
||||
pub fn iter_load_for_gen_module(
|
||||
&mut self,
|
||||
gen_subs: &mut Subs,
|
||||
should_load_def: impl Fn(Symbol) -> bool,
|
||||
) -> VecMap<Symbol, Expr> {
|
||||
self.map
|
||||
.values()
|
||||
.filter_map(|(symbol, def, _)| {
|
||||
if should_load_def(*symbol) {
|
||||
let (_new_expr_var, new_expr) = roc_can::copy::deep_copy_expr_across_subs(
|
||||
&mut self.subs,
|
||||
gen_subs,
|
||||
def.expr_var,
|
||||
&def.loc_expr.value,
|
||||
);
|
||||
Some((*symbol, new_expr))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// Prefer using a fresh Derived module with [`Derived::default`]. Use this only in testing.
|
||||
pub unsafe fn from_components(subs: Subs, ident_ids: IdentIds) -> Self {
|
||||
Self {
|
||||
map: Default::default(),
|
||||
subs,
|
||||
derived_ident_ids: ident_ids,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decompose(self) -> (Subs, IdentIds) {
|
||||
(self.subs, self.derived_ident_ids)
|
||||
}
|
||||
}
|
||||
|
||||
/// Thread-sharable [`DerivedMethods`].
|
||||
/// Thread-sharable [`DerivedModule`].
|
||||
pub type SharedDerivedModule = Arc<Mutex<DerivedModule>>;
|
||||
|
|
|
@ -11,7 +11,4 @@ roc_error_macros = { path = "../../error_macros" }
|
|||
roc_region = { path = "../region" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_types = { path = "../types" }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
debug-derived-symbols = []
|
||||
roc_can = { path = "../can" }
|
||||
|
|
|
@ -15,12 +15,9 @@
|
|||
|
||||
pub mod encoding;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use encoding::{FlatEncodable, FlatEncodableKey};
|
||||
|
||||
use roc_collections::MutMap;
|
||||
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_types::subs::{Subs, Variable};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
@ -68,54 +65,3 @@ impl Derived {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Map of [`DeriveKey`]s to their derived symbols.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct DerivedSymbols {
|
||||
map: MutMap<DeriveKey, Symbol>,
|
||||
derived_ident_ids: IdentIds,
|
||||
#[cfg(debug_assertions)]
|
||||
stolen: bool,
|
||||
}
|
||||
|
||||
impl DerivedSymbols {
|
||||
pub fn get_or_insert(&mut self, key: DeriveKey) -> Symbol {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
debug_assert!(!self.stolen, "attempting to add to stolen symbols!");
|
||||
}
|
||||
|
||||
let symbol = self.map.entry(key).or_insert_with_key(|key| {
|
||||
let ident_id = if cfg!(debug_assertions) || cfg!(feature = "debug-derived-symbols") {
|
||||
let debug_name = key.debug_name();
|
||||
debug_assert!(
|
||||
self.derived_ident_ids.get_id(&debug_name).is_none(),
|
||||
"duplicate debug name for different derive key"
|
||||
);
|
||||
self.derived_ident_ids.get_or_insert(&debug_name)
|
||||
} else {
|
||||
self.derived_ident_ids.gen_unique()
|
||||
};
|
||||
|
||||
Symbol::new(ModuleId::DERIVED, ident_id)
|
||||
});
|
||||
*symbol
|
||||
}
|
||||
|
||||
/// Steal all created derived ident Ids.
|
||||
/// After this is called, [`Self::get_or_insert`] may no longer be called.
|
||||
pub fn steal(&mut self) -> IdentIds {
|
||||
let mut ident_ids = Default::default();
|
||||
std::mem::swap(&mut self.derived_ident_ids, &mut ident_ids);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
self.stolen = true;
|
||||
}
|
||||
|
||||
ident_ids
|
||||
}
|
||||
}
|
||||
|
||||
/// Thread-sharable [`DerivedMethods`].
|
||||
pub type GlobalDerivedSymbols = Arc<Mutex<DerivedSymbols>>;
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::llvm::build_list::{
|
|||
list_prepend, list_replace_unsafe, list_reserve, list_sort_with, list_sublist, list_swap,
|
||||
list_symbol_to_c_abi, list_to_c_abi, list_with_capacity, pass_update_mode,
|
||||
};
|
||||
use crate::llvm::build_str::{str_from_float, str_from_int};
|
||||
use crate::llvm::build_str::{dec_to_str, str_from_float, str_from_int};
|
||||
use crate::llvm::compare::{generic_eq, generic_neq};
|
||||
use crate::llvm::convert::{
|
||||
self, argument_type_from_layout, basic_type_from_builtin, basic_type_from_layout,
|
||||
|
@ -5434,7 +5434,14 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
// Str.fromFloat : Float * -> Str
|
||||
debug_assert_eq!(args.len(), 1);
|
||||
|
||||
str_from_float(env, scope, args[0])
|
||||
let (float, float_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||
|
||||
let float_width = match float_layout {
|
||||
Layout::Builtin(Builtin::Float(float_width)) => *float_width,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
str_from_float(env, float, float_width)
|
||||
}
|
||||
StrFromUtf8Range => {
|
||||
debug_assert_eq!(args.len(), 3);
|
||||
|
@ -5768,9 +5775,10 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
|
||||
str_from_int(env, int, *int_width)
|
||||
}
|
||||
Layout::Builtin(Builtin::Float(_float_width)) => {
|
||||
str_from_float(env, scope, args[0])
|
||||
Layout::Builtin(Builtin::Float(float_width)) => {
|
||||
str_from_float(env, num, *float_width)
|
||||
}
|
||||
Layout::Builtin(Builtin::Decimal) => dec_to_str(env, num),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::llvm::build::{Env, Scope};
|
|||
use inkwell::builder::Builder;
|
||||
use inkwell::values::{BasicValueEnum, IntValue, PointerValue, StructValue};
|
||||
use inkwell::AddressSpace;
|
||||
use roc_builtins::bitcode::{self, IntWidth};
|
||||
use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout};
|
||||
use roc_target::PtrWidth;
|
||||
|
@ -103,15 +103,37 @@ pub fn decode_from_utf8_result<'a, 'ctx, 'env>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Str.fromFloat : Int -> Str
|
||||
/// Str.fromFloat : Float * -> Str
|
||||
pub fn str_from_float<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
scope: &Scope<'a, 'ctx>,
|
||||
int_symbol: Symbol,
|
||||
float: BasicValueEnum<'ctx>,
|
||||
float_width: FloatWidth,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let float = load_symbol(scope, &int_symbol);
|
||||
call_str_bitcode_fn(env, &[float], &bitcode::STR_FROM_FLOAT[float_width])
|
||||
}
|
||||
|
||||
call_str_bitcode_fn(env, &[float], bitcode::STR_FROM_FLOAT)
|
||||
/// Dec.toStr : Dec -> Str
|
||||
pub fn dec_to_str<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
dec: BasicValueEnum<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let dec = dec.into_int_value();
|
||||
|
||||
let int_64 = env.context.i128_type().const_int(64, false);
|
||||
let int_64_type = env.context.i64_type();
|
||||
|
||||
let dec_right_shift = env
|
||||
.builder
|
||||
.build_right_shift(dec, int_64, false, "dec_left_bits");
|
||||
|
||||
let right_bits = env.builder.build_int_cast(dec, int_64_type, "");
|
||||
let left_bits = env.builder.build_int_cast(dec_right_shift, int_64_type, "");
|
||||
|
||||
call_str_bitcode_fn(
|
||||
env,
|
||||
&[right_bits.into(), left_bits.into()],
|
||||
bitcode::DEC_TO_STR,
|
||||
)
|
||||
}
|
||||
|
||||
/// Str.equal : Str, Str -> Bool
|
||||
|
|
|
@ -1983,15 +1983,15 @@ impl<'a> LowLevelCall<'a> {
|
|||
FloatWidth::F32 => {
|
||||
self.load_args(backend);
|
||||
backend.code_builder.f64_promote_f32();
|
||||
self.load_args_and_call_zig(backend, bitcode::STR_FROM_FLOAT);
|
||||
self.load_args_and_call_zig(backend, &bitcode::STR_FROM_FLOAT[width]);
|
||||
}
|
||||
FloatWidth::F64 => {
|
||||
self.load_args_and_call_zig(backend, bitcode::STR_FROM_FLOAT);
|
||||
self.load_args_and_call_zig(backend, &bitcode::STR_FROM_FLOAT[width]);
|
||||
}
|
||||
FloatWidth::F128 => todo!("F128 to Str"),
|
||||
},
|
||||
Layout::Builtin(Builtin::Decimal) => {
|
||||
todo!("Decimal to Str")
|
||||
self.load_args_and_call_zig(backend, bitcode::DEC_TO_STR)
|
||||
}
|
||||
x => internal_error!("NumToStr is not defined for {:?}", x),
|
||||
}
|
||||
|
|
|
@ -8,9 +8,10 @@ edition = "2021"
|
|||
[dependencies]
|
||||
roc_types = { path = "../types" }
|
||||
roc_can = { path = "../can" }
|
||||
roc_derive_key = { path = "../derive_key" }
|
||||
roc_derive = { path = "../derive" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_unify = { path = "../unify" }
|
||||
roc_solve = { path = "../solve" }
|
||||
roc_collections = { path = "../collections" }
|
||||
roc_error_macros = { path = "../../error_macros" }
|
||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||
|
|
|
@ -5,8 +5,10 @@ use std::sync::{Arc, RwLock};
|
|||
|
||||
use bumpalo::Bump;
|
||||
use roc_can::abilities::AbilitiesStore;
|
||||
use roc_can::module::ExposedByModule;
|
||||
use roc_collections::MutMap;
|
||||
use roc_derive_key::GlobalDerivedSymbols;
|
||||
use roc_derive::SharedDerivedModule;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::symbol::ModuleId;
|
||||
use roc_solve::solve::{compact_lambda_sets_of_vars, Phase, Pools};
|
||||
use roc_types::subs::{Content, FlatType, LambdaSet};
|
||||
|
@ -45,6 +47,30 @@ impl WorldAbilities {
|
|||
debug_assert!(old_store.is_none(), "{:?} abilities not new", module);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn with_module_exposed_type<T>(
|
||||
&mut self,
|
||||
module: ModuleId,
|
||||
mut f: impl FnMut(&mut ExposedTypesStorageSubs) -> T,
|
||||
) -> T {
|
||||
let mut world = self.world.write().unwrap();
|
||||
let (_, exposed_types) = world.get_mut(&module).expect("module not in the world");
|
||||
|
||||
f(exposed_types)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn with_module_abilities_store<T, F>(&self, module: ModuleId, mut f: F) -> T
|
||||
where
|
||||
F: FnMut(&AbilitiesStore) -> T,
|
||||
{
|
||||
let world = self.world.read().unwrap();
|
||||
let (module_store, _module_types) = world
|
||||
.get(&module)
|
||||
.unwrap_or_else(|| internal_error!("Module {:?} not found in world abilities", module));
|
||||
f(module_store)
|
||||
}
|
||||
|
||||
pub fn clone_ref(&self) -> Self {
|
||||
Self {
|
||||
world: Arc::clone(&self.world),
|
||||
|
@ -53,7 +79,7 @@ impl WorldAbilities {
|
|||
}
|
||||
|
||||
pub enum AbilitiesView<'a> {
|
||||
World(WorldAbilities),
|
||||
World(&'a WorldAbilities),
|
||||
Module(&'a AbilitiesStore),
|
||||
}
|
||||
|
||||
|
@ -64,11 +90,7 @@ impl AbilitiesView<'_> {
|
|||
F: FnMut(&AbilitiesStore) -> T,
|
||||
{
|
||||
match self {
|
||||
AbilitiesView::World(wa) => {
|
||||
let world = wa.world.read().unwrap();
|
||||
let (module_store, _module_types) = world.get(&module).unwrap();
|
||||
f(module_store)
|
||||
}
|
||||
AbilitiesView::World(wa) => wa.with_module_abilities_store(module, f),
|
||||
AbilitiesView::Module(store) => f(store),
|
||||
}
|
||||
}
|
||||
|
@ -142,16 +164,24 @@ impl Phase for LatePhase<'_> {
|
|||
|
||||
/// Unifies two variables and performs lambda set compaction.
|
||||
/// Ranks and other ability demands are disregarded.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn unify(
|
||||
home: ModuleId,
|
||||
arena: &Bump,
|
||||
subs: &mut Subs,
|
||||
abilities: &AbilitiesView,
|
||||
derived_symbols: &GlobalDerivedSymbols,
|
||||
derived_module: &SharedDerivedModule,
|
||||
exposed_by_module: &ExposedByModule,
|
||||
left: Variable,
|
||||
right: Variable,
|
||||
) -> Result<(), UnificationFailed> {
|
||||
debug_assert_ne!(
|
||||
home,
|
||||
ModuleId::DERIVED_SYNTH,
|
||||
"derived module can only unify its subs in its own context!"
|
||||
);
|
||||
let unified = unify_unify(subs, left, right, Mode::EQ);
|
||||
|
||||
match unified {
|
||||
Unified::Success {
|
||||
vars: _,
|
||||
|
@ -165,11 +195,12 @@ pub fn unify(
|
|||
|
||||
let must_implement_constraints = compact_lambda_sets_of_vars(
|
||||
subs,
|
||||
derived_module,
|
||||
arena,
|
||||
&mut pools,
|
||||
lambda_sets_to_specialize,
|
||||
&late_phase,
|
||||
derived_symbols,
|
||||
exposed_by_module,
|
||||
);
|
||||
// At this point we can't do anything with must-implement constraints, since we're no
|
||||
// longer solving. We must assume that they were totally caught during solving.
|
||||
|
|
|
@ -92,7 +92,6 @@ pub fn load_and_monomorphize_from_str<'a>(
|
|||
pub fn load_and_monomorphize(
|
||||
arena: &Bump,
|
||||
filename: PathBuf,
|
||||
src_dir: PathBuf,
|
||||
exposed_types: ExposedByModule,
|
||||
target_info: TargetInfo,
|
||||
render: RenderTarget,
|
||||
|
@ -100,7 +99,7 @@ pub fn load_and_monomorphize(
|
|||
) -> Result<MonomorphizedModule<'_>, LoadingProblem<'_>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_path(arena, src_dir, filename, render)?;
|
||||
let load_start = LoadStart::from_path(arena, filename, render)?;
|
||||
|
||||
match load(
|
||||
arena,
|
||||
|
@ -119,7 +118,6 @@ pub fn load_and_monomorphize(
|
|||
pub fn load_and_typecheck(
|
||||
arena: &Bump,
|
||||
filename: PathBuf,
|
||||
src_dir: PathBuf,
|
||||
exposed_types: ExposedByModule,
|
||||
target_info: TargetInfo,
|
||||
render: RenderTarget,
|
||||
|
@ -127,7 +125,7 @@ pub fn load_and_typecheck(
|
|||
) -> Result<LoadedModule, LoadingProblem<'_>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_path(arena, src_dir, filename, render)?;
|
||||
let load_start = LoadStart::from_path(arena, filename, render)?;
|
||||
|
||||
match load(
|
||||
arena,
|
||||
|
|
|
@ -14,6 +14,7 @@ roc_types = { path = "../types" }
|
|||
roc_can = { path = "../can" }
|
||||
roc_constrain = { path = "../constrain" }
|
||||
roc_derive_key = { path = "../derive_key" }
|
||||
roc_derive = { path = "../derive" }
|
||||
roc_builtins = { path = "../builtins" }
|
||||
roc_problem = { path = "../problem" }
|
||||
roc_unify = { path = "../unify" }
|
||||
|
|
|
@ -20,7 +20,7 @@ use roc_debug_flags::{
|
|||
ROC_PRINT_IR_AFTER_REFCOUNT, ROC_PRINT_IR_AFTER_RESET_REUSE, ROC_PRINT_IR_AFTER_SPECIALIZATION,
|
||||
ROC_PRINT_LOAD_LOG,
|
||||
};
|
||||
use roc_derive_key::GlobalDerivedSymbols;
|
||||
use roc_derive::SharedDerivedModule;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_late_solve::{AbilitiesView, WorldAbilities};
|
||||
use roc_module::ident::{Ident, ModuleName, QualifiedModuleName};
|
||||
|
@ -370,7 +370,7 @@ fn start_phase<'a>(
|
|||
..
|
||||
} = constrained;
|
||||
|
||||
let derived_symbols = GlobalDerivedSymbols::clone(&state.derived_symbols);
|
||||
let derived_module = SharedDerivedModule::clone(&state.derived_module);
|
||||
|
||||
BuildTask::solve_module(
|
||||
module,
|
||||
|
@ -385,7 +385,7 @@ fn start_phase<'a>(
|
|||
dep_idents,
|
||||
declarations,
|
||||
state.cached_subs.clone(),
|
||||
derived_symbols,
|
||||
derived_module,
|
||||
)
|
||||
}
|
||||
Phase::FindSpecializations => {
|
||||
|
@ -413,7 +413,7 @@ fn start_phase<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
let derived_symbols = GlobalDerivedSymbols::clone(&state.derived_symbols);
|
||||
let derived_module = SharedDerivedModule::clone(&state.derived_module);
|
||||
|
||||
BuildTask::BuildPendingSpecializations {
|
||||
layout_cache,
|
||||
|
@ -425,18 +425,44 @@ fn start_phase<'a>(
|
|||
ident_ids,
|
||||
exposed_to_host: state.exposed_to_host.clone(),
|
||||
abilities_store,
|
||||
derived_symbols,
|
||||
// TODO: awful, how can we get rid of the clone?
|
||||
exposed_by_module: state.exposed_types.clone(),
|
||||
derived_module,
|
||||
}
|
||||
}
|
||||
Phase::MakeSpecializations => {
|
||||
let specializations_we_must_make = state
|
||||
let mut specializations_we_must_make = state
|
||||
.module_cache
|
||||
.external_specializations_requested
|
||||
.remove(&module_id)
|
||||
.unwrap_or_default();
|
||||
|
||||
let (ident_ids, subs, procs_base, layout_cache, module_timing) =
|
||||
if state.make_specializations_pass.current_pass() == 1 {
|
||||
if module_id == ModuleId::DERIVED_GEN {
|
||||
// The derived gen module must also fulfill also specializations asked of the
|
||||
// derived synth module.
|
||||
let derived_synth_specializations = state
|
||||
.module_cache
|
||||
.external_specializations_requested
|
||||
.remove(&ModuleId::DERIVED_SYNTH)
|
||||
.unwrap_or_default();
|
||||
specializations_we_must_make.extend(derived_synth_specializations)
|
||||
}
|
||||
|
||||
let (mut ident_ids, mut subs, mut procs_base, layout_cache, mut module_timing) =
|
||||
if state.make_specializations_pass.current_pass() == 1
|
||||
&& module_id == ModuleId::DERIVED_GEN
|
||||
{
|
||||
// This is the first time the derived module is introduced into the load
|
||||
// graph. It has no abilities of its own or anything, just generate fresh
|
||||
// information for it.
|
||||
(
|
||||
IdentIds::default(),
|
||||
Subs::default(),
|
||||
ProcsBase::default(),
|
||||
LayoutCache::new(state.target_info),
|
||||
ModuleTiming::new(SystemTime::now()),
|
||||
)
|
||||
} else if state.make_specializations_pass.current_pass() == 1 {
|
||||
let found_specializations = state
|
||||
.module_cache
|
||||
.found_specializations
|
||||
|
@ -452,12 +478,13 @@ fn start_phase<'a>(
|
|||
abilities_store,
|
||||
} = found_specializations;
|
||||
|
||||
// Safety: by this point every module should have been solved, so there is no need
|
||||
// for our exposed types anymore, but the world does need them.
|
||||
let our_exposed_types = unsafe { state.exposed_types.remove(&module_id) }
|
||||
let our_exposed_types = state
|
||||
.exposed_types
|
||||
.get(&module_id)
|
||||
.unwrap_or_else(|| {
|
||||
internal_error!("Exposed types for {:?} missing", module_id)
|
||||
});
|
||||
})
|
||||
.clone();
|
||||
|
||||
// Add our abilities to the world.
|
||||
state.world_abilities.insert(
|
||||
|
@ -483,7 +510,22 @@ fn start_phase<'a>(
|
|||
(ident_ids, subs, procs_base, layout_cache, module_timing)
|
||||
};
|
||||
|
||||
let derived_symbols = GlobalDerivedSymbols::clone(&state.derived_symbols);
|
||||
if module_id == ModuleId::DERIVED_GEN {
|
||||
load_derived_partial_procs(
|
||||
module_id,
|
||||
arena,
|
||||
&mut subs,
|
||||
&mut ident_ids,
|
||||
&state.derived_module,
|
||||
&mut module_timing,
|
||||
state.target_info,
|
||||
&state.exposed_types,
|
||||
&mut procs_base,
|
||||
&mut state.world_abilities,
|
||||
);
|
||||
}
|
||||
|
||||
let derived_module = SharedDerivedModule::clone(&state.derived_module);
|
||||
|
||||
BuildTask::MakeSpecializations {
|
||||
module_id,
|
||||
|
@ -494,7 +536,9 @@ fn start_phase<'a>(
|
|||
specializations_we_must_make,
|
||||
module_timing,
|
||||
world_abilities: state.world_abilities.clone_ref(),
|
||||
derived_symbols,
|
||||
// TODO: awful, how can we get rid of the clone?
|
||||
exposed_by_module: state.exposed_types.clone(),
|
||||
derived_module,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -808,7 +852,7 @@ struct State<'a> {
|
|||
pub arc_modules: Arc<Mutex<PackageModuleIds<'a>>>,
|
||||
pub arc_shorthands: Arc<Mutex<MutMap<&'a str, PackageName<'a>>>>,
|
||||
#[allow(unused)]
|
||||
pub derived_symbols: GlobalDerivedSymbols,
|
||||
pub derived_module: SharedDerivedModule,
|
||||
|
||||
pub ident_ids_by_module: SharedIdentIdsByModule,
|
||||
|
||||
|
@ -853,6 +897,8 @@ impl<'a> State<'a> {
|
|||
) -> Self {
|
||||
let arc_shorthands = Arc::new(Mutex::new(MutMap::default()));
|
||||
|
||||
let dependencies = Dependencies::new(goal_phase);
|
||||
|
||||
Self {
|
||||
root_id,
|
||||
root_subs: None,
|
||||
|
@ -862,14 +908,14 @@ impl<'a> State<'a> {
|
|||
output_path: None,
|
||||
platform_path: PlatformPath::NotSpecified,
|
||||
module_cache: ModuleCache::default(),
|
||||
dependencies: Dependencies::default(),
|
||||
dependencies,
|
||||
procedures: MutMap::default(),
|
||||
toplevel_expects: Vec::new(),
|
||||
exposed_to_host: ExposedToHost::default(),
|
||||
exposed_types,
|
||||
arc_modules,
|
||||
arc_shorthands,
|
||||
derived_symbols: Default::default(),
|
||||
derived_module: Default::default(),
|
||||
constrained_ident_ids: IdentIds::exposed_builtins(0),
|
||||
ident_ids_by_module,
|
||||
declarations_by_id: MutMap::default(),
|
||||
|
@ -988,7 +1034,7 @@ enum BuildTask<'a> {
|
|||
declarations: Declarations,
|
||||
dep_idents: IdentIdsByModule,
|
||||
cached_subs: CachedSubs,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
derived_module: SharedDerivedModule,
|
||||
},
|
||||
BuildPendingSpecializations {
|
||||
module_timing: ModuleTiming,
|
||||
|
@ -999,8 +1045,9 @@ enum BuildTask<'a> {
|
|||
ident_ids: IdentIds,
|
||||
decls: Declarations,
|
||||
exposed_to_host: ExposedToHost,
|
||||
exposed_by_module: ExposedByModule,
|
||||
abilities_store: AbilitiesStore,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
derived_module: SharedDerivedModule,
|
||||
},
|
||||
MakeSpecializations {
|
||||
module_id: ModuleId,
|
||||
|
@ -1010,8 +1057,9 @@ enum BuildTask<'a> {
|
|||
layout_cache: LayoutCache<'a>,
|
||||
specializations_we_must_make: Vec<ExternalSpecializations<'a>>,
|
||||
module_timing: ModuleTiming,
|
||||
exposed_by_module: ExposedByModule,
|
||||
world_abilities: WorldAbilities,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
derived_module: SharedDerivedModule,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1114,13 +1162,13 @@ pub struct LoadStart<'a> {
|
|||
impl<'a> LoadStart<'a> {
|
||||
pub fn from_path(
|
||||
arena: &'a Bump,
|
||||
mut src_dir: PathBuf,
|
||||
filename: PathBuf,
|
||||
render: RenderTarget,
|
||||
) -> Result<Self, LoadingProblem<'a>> {
|
||||
let arc_modules = Arc::new(Mutex::new(PackageModuleIds::default()));
|
||||
let root_exposed_ident_ids = IdentIds::exposed_builtins(0);
|
||||
let ident_ids_by_module = Arc::new(Mutex::new(root_exposed_ident_ids));
|
||||
let mut src_dir = filename.parent().unwrap().to_path_buf();
|
||||
|
||||
// Load the root module synchronously; we can't proceed until we have its id.
|
||||
let (root_id, root_msg) = {
|
||||
|
@ -2637,7 +2685,16 @@ fn finish_specialization(
|
|||
.into_inner()
|
||||
.into_module_ids();
|
||||
|
||||
let all_ident_ids = state.constrained_ident_ids;
|
||||
let mut all_ident_ids = state.constrained_ident_ids;
|
||||
|
||||
// Associate the ident IDs from the derived synth module
|
||||
let (_, derived_synth_ident_ids) = Arc::try_unwrap(state.derived_module)
|
||||
.unwrap_or_else(|_| internal_error!("Outstanding references to the derived module"))
|
||||
.into_inner()
|
||||
.unwrap()
|
||||
.decompose();
|
||||
ModuleId::DERIVED_SYNTH.register_debug_idents(&derived_synth_ident_ids);
|
||||
all_ident_ids.insert(ModuleId::DERIVED_SYNTH, derived_synth_ident_ids);
|
||||
|
||||
let interns = Interns {
|
||||
module_ids,
|
||||
|
@ -2755,12 +2812,16 @@ fn finish(
|
|||
.into_inner()
|
||||
.into_module_ids();
|
||||
|
||||
// Steal the derived symbols and put them in the global ident ids
|
||||
let derived_ident_ids = state.derived_symbols.lock().unwrap().steal();
|
||||
ModuleId::DERIVED.register_debug_idents(&derived_ident_ids);
|
||||
// Associate the ident IDs from the derived synth module
|
||||
let (_, derived_synth_ident_ids) = Arc::try_unwrap(state.derived_module)
|
||||
.unwrap_or_else(|_| internal_error!("Outstanding references to the derived module"))
|
||||
.into_inner()
|
||||
.unwrap()
|
||||
.decompose();
|
||||
ModuleId::DERIVED_SYNTH.register_debug_idents(&derived_synth_ident_ids);
|
||||
state
|
||||
.constrained_ident_ids
|
||||
.insert(ModuleId::DERIVED, derived_ident_ids);
|
||||
.insert(ModuleId::DERIVED_SYNTH, derived_synth_ident_ids);
|
||||
|
||||
let interns = Interns {
|
||||
module_ids,
|
||||
|
@ -2847,7 +2908,7 @@ fn load_platform_module<'a>(
|
|||
// make a `platform` module that ultimately exposes `main` to the host
|
||||
let platform_module_msg = fabricate_platform_module(
|
||||
arena,
|
||||
shorthand,
|
||||
Some(shorthand),
|
||||
Some(app_module_id),
|
||||
filename.to_path_buf(),
|
||||
parser_state,
|
||||
|
@ -3245,19 +3306,17 @@ fn parse_header<'a>(
|
|||
To::NewPackage(_package_name) => Ok((module_id, app_module_header_msg)),
|
||||
}
|
||||
}
|
||||
Ok((ast::Module::Platform { header }, parse_state)) => {
|
||||
Ok(fabricate_platform_module(
|
||||
arena,
|
||||
"", // Use a shorthand of "" - it will be fine for `roc check` and bindgen
|
||||
None,
|
||||
filename,
|
||||
parse_state,
|
||||
module_ids.clone(),
|
||||
ident_ids_by_module,
|
||||
&header,
|
||||
module_timing,
|
||||
))
|
||||
}
|
||||
Ok((ast::Module::Platform { header }, parse_state)) => Ok(fabricate_platform_module(
|
||||
arena,
|
||||
None,
|
||||
None,
|
||||
filename,
|
||||
parse_state,
|
||||
module_ids.clone(),
|
||||
ident_ids_by_module,
|
||||
&header,
|
||||
module_timing,
|
||||
)),
|
||||
|
||||
Err(fail) => Err(LoadingProblem::ParsingFailed(
|
||||
fail.map_problem(SyntaxError::Header)
|
||||
|
@ -3542,7 +3601,7 @@ fn send_header<'a>(
|
|||
struct PlatformHeaderInfo<'a> {
|
||||
filename: PathBuf,
|
||||
is_root_module: bool,
|
||||
shorthand: &'a str,
|
||||
opt_shorthand: Option<&'a str>,
|
||||
opt_app_module_id: Option<ModuleId>,
|
||||
packages: &'a [Loc<PackageEntry<'a>>],
|
||||
provides: &'a [Loc<ExposedName<'a>>],
|
||||
|
@ -3562,7 +3621,7 @@ fn send_header_two<'a>(
|
|||
) -> (ModuleId, Msg<'a>) {
|
||||
let PlatformHeaderInfo {
|
||||
filename,
|
||||
shorthand,
|
||||
opt_shorthand,
|
||||
is_root_module,
|
||||
opt_app_module_id,
|
||||
packages,
|
||||
|
@ -3617,7 +3676,10 @@ fn send_header_two<'a>(
|
|||
let mut module_ids = (*module_ids).lock();
|
||||
let mut ident_ids_by_module = (*ident_ids_by_module).lock();
|
||||
|
||||
let name = PQModuleName::Qualified(shorthand, declared_name);
|
||||
let name = match opt_shorthand {
|
||||
Some(shorthand) => PQModuleName::Qualified(shorthand, declared_name),
|
||||
None => PQModuleName::Unqualified(declared_name),
|
||||
};
|
||||
home = module_ids.get_or_insert(&name);
|
||||
|
||||
// Ensure this module has an entry in the exposed_ident_ids map.
|
||||
|
@ -3631,8 +3693,13 @@ fn send_header_two<'a>(
|
|||
for (qualified_module_name, exposed_idents, region) in imported.into_iter() {
|
||||
let cloned_module_name = qualified_module_name.module.clone();
|
||||
let pq_module_name = match qualified_module_name.opt_package {
|
||||
None => PQModuleName::Qualified(shorthand, qualified_module_name.module),
|
||||
Some(package) => PQModuleName::Qualified(package, cloned_module_name.clone()),
|
||||
None => match opt_shorthand {
|
||||
Some(shorthand) => {
|
||||
PQModuleName::Qualified(shorthand, qualified_module_name.module)
|
||||
}
|
||||
None => PQModuleName::Unqualified(qualified_module_name.module),
|
||||
},
|
||||
Some(package) => PQModuleName::Qualified(package, cloned_module_name),
|
||||
};
|
||||
|
||||
let module_id = module_ids.get_or_insert(&pq_module_name);
|
||||
|
@ -3741,7 +3808,8 @@ fn send_header_two<'a>(
|
|||
};
|
||||
|
||||
let extra = HeaderFor::Platform {
|
||||
config_shorthand: shorthand,
|
||||
// A config_shorthand of "" should be fine
|
||||
config_shorthand: opt_shorthand.unwrap_or_default(),
|
||||
platform_main_type: requires[0].value,
|
||||
main_for_host,
|
||||
};
|
||||
|
@ -3798,7 +3866,7 @@ impl<'a> BuildTask<'a> {
|
|||
dep_idents: IdentIdsByModule,
|
||||
declarations: Declarations,
|
||||
cached_subs: CachedSubs,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
derived_module: SharedDerivedModule,
|
||||
) -> Self {
|
||||
let exposed_by_module = exposed_types.retain_modules(imported_modules.keys());
|
||||
|
||||
|
@ -3818,7 +3886,7 @@ impl<'a> BuildTask<'a> {
|
|||
dep_idents,
|
||||
module_timing,
|
||||
cached_subs,
|
||||
derived_symbols,
|
||||
derived_module,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3866,7 +3934,7 @@ pub fn add_imports(
|
|||
my_module: ModuleId,
|
||||
subs: &mut Subs,
|
||||
mut pending_abilities: PendingAbilitiesStore,
|
||||
mut exposed_for_module: ExposedForModule,
|
||||
exposed_for_module: &ExposedForModule,
|
||||
def_types: &mut Vec<(Symbol, Loc<roc_types::types::Type>)>,
|
||||
rigid_vars: &mut Vec<Variable>,
|
||||
) -> (Vec<Variable>, AbilitiesStore) {
|
||||
|
@ -3879,7 +3947,7 @@ pub fn add_imports(
|
|||
macro_rules! import_var_for_symbol {
|
||||
($subs:expr, $exposed_by_module:expr, $symbol:ident, $break:stmt) => {
|
||||
let module_id = $symbol.module_id();
|
||||
match $exposed_by_module.get_mut(&module_id) {
|
||||
match $exposed_by_module.get(&module_id) {
|
||||
Some(ExposedModuleTypes {
|
||||
exposed_types_storage_subs: exposed_types,
|
||||
resolved_specializations: _,
|
||||
|
@ -3922,7 +3990,7 @@ pub fn add_imports(
|
|||
}
|
||||
}
|
||||
|
||||
for symbol in exposed_for_module.imported_values {
|
||||
for &symbol in &exposed_for_module.imported_values {
|
||||
import_var_for_symbol!(subs, exposed_for_module.exposed_by_module, symbol, continue);
|
||||
}
|
||||
|
||||
|
@ -3948,14 +4016,14 @@ pub fn add_imports(
|
|||
|
||||
struct Ctx<'a> {
|
||||
subs: &'a mut Subs,
|
||||
exposed_by_module: &'a mut ExposedByModule,
|
||||
exposed_by_module: &'a ExposedByModule,
|
||||
}
|
||||
|
||||
let abilities_store = pending_abilities.resolve_for_module(
|
||||
my_module,
|
||||
&mut Ctx {
|
||||
subs,
|
||||
exposed_by_module: &mut exposed_for_module.exposed_by_module,
|
||||
exposed_by_module: &exposed_for_module.exposed_by_module,
|
||||
},
|
||||
|ctx, symbol| match cached_symbol_vars.get(&symbol).copied() {
|
||||
Some(var) => var,
|
||||
|
@ -3969,7 +4037,7 @@ pub fn add_imports(
|
|||
*cached_symbol_vars.get(&symbol).unwrap()
|
||||
}
|
||||
},
|
||||
|ctx, module, lset_var| match ctx.exposed_by_module.get_mut(&module) {
|
||||
|ctx, module, lset_var| match ctx.exposed_by_module.get(&module) {
|
||||
Some(ExposedModuleTypes {
|
||||
exposed_types_storage_subs: exposed_types,
|
||||
resolved_specializations: _,
|
||||
|
@ -4000,7 +4068,7 @@ fn run_solve_solve(
|
|||
pending_derives: PendingDerives,
|
||||
var_store: VarStore,
|
||||
module: Module,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
derived_module: SharedDerivedModule,
|
||||
) -> (
|
||||
Solved<Subs>,
|
||||
ResolvedSpecializations,
|
||||
|
@ -4025,7 +4093,7 @@ fn run_solve_solve(
|
|||
module.module_id,
|
||||
&mut subs,
|
||||
pending_abilities,
|
||||
exposed_for_module,
|
||||
&exposed_for_module,
|
||||
&mut def_types,
|
||||
&mut rigid_vars,
|
||||
);
|
||||
|
@ -4040,7 +4108,10 @@ fn run_solve_solve(
|
|||
}
|
||||
|
||||
let (solved_subs, solved_specializations, exposed_vars_by_symbol, problems, abilities_store) = {
|
||||
let module_id = module.module_id;
|
||||
|
||||
let (solved_subs, solved_env, problems, abilities_store) = roc_solve::module::run_solve(
|
||||
module_id,
|
||||
&constraints,
|
||||
actual_constraint,
|
||||
rigid_variables,
|
||||
|
@ -4048,10 +4119,10 @@ fn run_solve_solve(
|
|||
solve_aliases,
|
||||
abilities_store,
|
||||
pending_derives,
|
||||
derived_symbols,
|
||||
&exposed_for_module.exposed_by_module,
|
||||
derived_module,
|
||||
);
|
||||
|
||||
let module_id = module.module_id;
|
||||
// Figure out what specializations belong to this module
|
||||
let solved_specializations: ResolvedSpecializations = abilities_store
|
||||
.iter_specializations()
|
||||
|
@ -4104,7 +4175,7 @@ fn run_solve<'a>(
|
|||
decls: Declarations,
|
||||
dep_idents: IdentIdsByModule,
|
||||
cached_subs: CachedSubs,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
derived_module: SharedDerivedModule,
|
||||
) -> Msg<'a> {
|
||||
let solve_start = SystemTime::now();
|
||||
|
||||
|
@ -4123,7 +4194,7 @@ fn run_solve<'a>(
|
|||
pending_derives,
|
||||
var_store,
|
||||
module,
|
||||
derived_symbols,
|
||||
derived_module,
|
||||
),
|
||||
Some((subs, exposed_vars_by_symbol)) => {
|
||||
(
|
||||
|
@ -4145,7 +4216,7 @@ fn run_solve<'a>(
|
|||
pending_derives,
|
||||
var_store,
|
||||
module,
|
||||
derived_symbols,
|
||||
derived_module,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
@ -4195,7 +4266,7 @@ fn unspace<'a, T: Copy>(arena: &'a Bump, items: &[Loc<Spaced<'a, T>>]) -> &'a [L
|
|||
#[allow(clippy::too_many_arguments)]
|
||||
fn fabricate_platform_module<'a>(
|
||||
arena: &'a Bump,
|
||||
shorthand: &'a str,
|
||||
opt_shorthand: Option<&'a str>,
|
||||
opt_app_module_id: Option<ModuleId>,
|
||||
filename: PathBuf,
|
||||
parse_state: roc_parse::state::State<'a>,
|
||||
|
@ -4211,7 +4282,7 @@ fn fabricate_platform_module<'a>(
|
|||
let info = PlatformHeaderInfo {
|
||||
filename,
|
||||
is_root_module,
|
||||
shorthand,
|
||||
opt_shorthand,
|
||||
opt_app_module_id,
|
||||
packages: &[],
|
||||
provides: unspace(arena, header.provides.items),
|
||||
|
@ -4507,7 +4578,8 @@ fn make_specializations<'a>(
|
|||
mut module_timing: ModuleTiming,
|
||||
target_info: TargetInfo,
|
||||
world_abilities: WorldAbilities,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
exposed_by_module: &ExposedByModule,
|
||||
derived_module: SharedDerivedModule,
|
||||
) -> Msg<'a> {
|
||||
let make_specializations_start = SystemTime::now();
|
||||
let mut update_mode_ids = UpdateModeIds::new();
|
||||
|
@ -4521,8 +4593,9 @@ fn make_specializations<'a>(
|
|||
update_mode_ids: &mut update_mode_ids,
|
||||
// call_specialization_counter=0 is reserved
|
||||
call_specialization_counter: 1,
|
||||
abilities: AbilitiesView::World(world_abilities),
|
||||
derived_symbols: &derived_symbols,
|
||||
abilities: AbilitiesView::World(&world_abilities),
|
||||
exposed_by_module,
|
||||
derived_module: &derived_module,
|
||||
};
|
||||
|
||||
let mut procs = Procs::new_in(arena);
|
||||
|
@ -4584,8 +4657,9 @@ fn build_pending_specializations<'a>(
|
|||
mut layout_cache: LayoutCache<'a>,
|
||||
target_info: TargetInfo,
|
||||
exposed_to_host: ExposedToHost,
|
||||
exposed_by_module: &ExposedByModule,
|
||||
abilities_store: AbilitiesStore,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
derived_module: SharedDerivedModule,
|
||||
) -> Msg<'a> {
|
||||
let find_specializations_start = SystemTime::now();
|
||||
|
||||
|
@ -4615,7 +4689,8 @@ fn build_pending_specializations<'a>(
|
|||
// to know the types and abilities in our modules. Only for building *all* specializations
|
||||
// do we need a global view.
|
||||
abilities: AbilitiesView::Module(&abilities_store),
|
||||
derived_symbols: &derived_symbols,
|
||||
exposed_by_module,
|
||||
derived_module: &derived_module,
|
||||
};
|
||||
|
||||
// Add modules' decls to Procs
|
||||
|
@ -4913,6 +4988,100 @@ fn build_pending_specializations<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Loads derived ability members up for specialization into the Derived module, prior to making
|
||||
/// their specializations.
|
||||
// TODO: right now, this runs sequentially, and no other modules are mono'd in parallel to the
|
||||
// derived module.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn load_derived_partial_procs<'a>(
|
||||
home: ModuleId,
|
||||
arena: &'a Bump,
|
||||
subs: &mut Subs,
|
||||
ident_ids: &mut IdentIds,
|
||||
derived_module: &SharedDerivedModule,
|
||||
module_timing: &mut ModuleTiming,
|
||||
target_info: TargetInfo,
|
||||
exposed_by_module: &ExposedByModule,
|
||||
procs_base: &mut ProcsBase<'a>,
|
||||
world_abilities: &mut WorldAbilities,
|
||||
) {
|
||||
debug_assert_eq!(home, ModuleId::DERIVED_GEN);
|
||||
|
||||
let load_derived_procs_start = SystemTime::now();
|
||||
|
||||
let mut new_module_thunks = bumpalo::collections::Vec::new_in(arena);
|
||||
|
||||
let mut update_mode_ids = UpdateModeIds::new();
|
||||
|
||||
let derives_to_add = {
|
||||
let mut derived_module = derived_module.lock().unwrap();
|
||||
|
||||
derived_module.iter_load_for_gen_module(subs, |symbol| {
|
||||
!procs_base.partial_procs.contains_key(&symbol)
|
||||
})
|
||||
};
|
||||
|
||||
// TODO: we can be even lazier here if we move `add_def_to_module` to happen in mono. Also, the
|
||||
// timings would be more accurate.
|
||||
for (derived_symbol, derived_expr) in derives_to_add.into_iter() {
|
||||
let mut mono_env = roc_mono::ir::Env {
|
||||
arena,
|
||||
subs,
|
||||
home,
|
||||
ident_ids,
|
||||
target_info,
|
||||
update_mode_ids: &mut update_mode_ids,
|
||||
// call_specialization_counter=0 is reserved
|
||||
call_specialization_counter: 1,
|
||||
// NB: for getting pending specializations the module view is enough because we only need
|
||||
// to know the types and abilities in our modules. Only for building *all* specializations
|
||||
// do we need a global view.
|
||||
abilities: AbilitiesView::World(world_abilities),
|
||||
exposed_by_module,
|
||||
derived_module,
|
||||
};
|
||||
|
||||
let partial_proc = match derived_expr {
|
||||
roc_can::expr::Expr::Closure(roc_can::expr::ClosureData {
|
||||
function_type,
|
||||
arguments,
|
||||
loc_body,
|
||||
captured_symbols,
|
||||
return_type,
|
||||
recursive,
|
||||
..
|
||||
}) => {
|
||||
debug_assert!(captured_symbols.is_empty());
|
||||
PartialProc::from_named_function(
|
||||
&mut mono_env,
|
||||
function_type,
|
||||
arguments.clone(),
|
||||
*loc_body,
|
||||
CapturedSymbols::None,
|
||||
recursive.is_recursive(),
|
||||
return_type,
|
||||
)
|
||||
}
|
||||
_ => internal_error!("Expected only functions to be derived"),
|
||||
};
|
||||
|
||||
procs_base
|
||||
.partial_procs
|
||||
.insert(derived_symbol, partial_proc);
|
||||
}
|
||||
|
||||
if !new_module_thunks.is_empty() {
|
||||
new_module_thunks.extend(procs_base.module_thunks);
|
||||
procs_base.module_thunks = new_module_thunks.into_bump_slice();
|
||||
}
|
||||
|
||||
let load_derived_procs_end = SystemTime::now();
|
||||
|
||||
module_timing.find_specializations = load_derived_procs_end
|
||||
.duration_since(load_derived_procs_start)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn run_task<'a>(
|
||||
task: BuildTask<'a>,
|
||||
arena: &'a Bump,
|
||||
|
@ -4972,7 +5141,7 @@ fn run_task<'a>(
|
|||
declarations,
|
||||
dep_idents,
|
||||
cached_subs,
|
||||
derived_symbols,
|
||||
derived_module,
|
||||
} => Ok(run_solve(
|
||||
module,
|
||||
ident_ids,
|
||||
|
@ -4985,7 +5154,7 @@ fn run_task<'a>(
|
|||
declarations,
|
||||
dep_idents,
|
||||
cached_subs,
|
||||
derived_symbols,
|
||||
derived_module,
|
||||
)),
|
||||
BuildPendingSpecializations {
|
||||
module_id,
|
||||
|
@ -4997,7 +5166,8 @@ fn run_task<'a>(
|
|||
imported_module_thunks,
|
||||
exposed_to_host,
|
||||
abilities_store,
|
||||
derived_symbols,
|
||||
exposed_by_module,
|
||||
derived_module,
|
||||
} => Ok(build_pending_specializations(
|
||||
arena,
|
||||
solved_subs,
|
||||
|
@ -5009,8 +5179,9 @@ fn run_task<'a>(
|
|||
layout_cache,
|
||||
target_info,
|
||||
exposed_to_host,
|
||||
&exposed_by_module,
|
||||
abilities_store,
|
||||
derived_symbols,
|
||||
derived_module,
|
||||
)),
|
||||
MakeSpecializations {
|
||||
module_id,
|
||||
|
@ -5021,7 +5192,8 @@ fn run_task<'a>(
|
|||
specializations_we_must_make,
|
||||
module_timing,
|
||||
world_abilities,
|
||||
derived_symbols,
|
||||
exposed_by_module,
|
||||
derived_module,
|
||||
} => Ok(make_specializations(
|
||||
arena,
|
||||
module_id,
|
||||
|
@ -5033,7 +5205,8 @@ fn run_task<'a>(
|
|||
module_timing,
|
||||
target_info,
|
||||
world_abilities,
|
||||
derived_symbols,
|
||||
&exposed_by_module,
|
||||
derived_module,
|
||||
)),
|
||||
}?;
|
||||
|
||||
|
|
|
@ -39,16 +39,87 @@ enum Job<'a> {
|
|||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct MakeSpecializationInfo {
|
||||
/// Modules to make specializations for after they are made for this module
|
||||
succ: MutSet<ModuleId>,
|
||||
/// Whether this module depends on specializations being made for another module
|
||||
has_pred: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct MakeSpecializationsDependents(MutMap<ModuleId, MakeSpecializationInfo>);
|
||||
|
||||
impl MakeSpecializationsDependents {
|
||||
/// Gets the info entry for a module, or creates a default one.
|
||||
fn entry(&mut self, module_id: ModuleId) -> &mut MakeSpecializationInfo {
|
||||
self.0.entry(module_id).or_default()
|
||||
}
|
||||
|
||||
fn mark_has_pred(&mut self, module_id: ModuleId) {
|
||||
self.entry(module_id).has_pred = true;
|
||||
}
|
||||
|
||||
fn add_succ(&mut self, module_id: ModuleId, succ: impl IntoIterator<Item = ModuleId>) {
|
||||
// Add make specialization dependents
|
||||
let entry = self.entry(module_id);
|
||||
debug_assert!(
|
||||
entry.succ.is_empty(),
|
||||
"already added successors for this module"
|
||||
);
|
||||
|
||||
entry.succ.extend(succ.into_iter());
|
||||
|
||||
// The module for derives implicitly depends on every other module
|
||||
entry.succ.insert(ModuleId::DERIVED_GEN);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MakeSpecializationsDependents {
|
||||
fn default() -> Self {
|
||||
let mut map: MutMap<ModuleId, MakeSpecializationInfo> = Default::default();
|
||||
|
||||
// The module for derives is always at the base as the last module to specialize
|
||||
map.insert(
|
||||
ModuleId::DERIVED_GEN,
|
||||
MakeSpecializationInfo {
|
||||
succ: Default::default(),
|
||||
// NB: invariant - the derived module depends on every other module, and
|
||||
// work can never be initiated for just the derived module!
|
||||
has_pred: true,
|
||||
},
|
||||
);
|
||||
|
||||
Self(map)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Dependencies<'a> {
|
||||
waiting_for: MutMap<Job<'a>, MutSet<Job<'a>>>,
|
||||
notifies: MutMap<Job<'a>, MutSet<Job<'a>>>,
|
||||
status: MutMap<Job<'a>, Status>,
|
||||
|
||||
/// module -> modules to make specializations after, whether a module comes before us
|
||||
make_specializations_dependents: MutMap<ModuleId, (MutSet<ModuleId>, bool)>,
|
||||
make_specializations_dependents: MakeSpecializationsDependents,
|
||||
}
|
||||
|
||||
impl<'a> Dependencies<'a> {
|
||||
pub fn new(goal_phase: Phase) -> Self {
|
||||
let mut deps = Self {
|
||||
waiting_for: Default::default(),
|
||||
notifies: Default::default(),
|
||||
status: Default::default(),
|
||||
make_specializations_dependents: Default::default(),
|
||||
};
|
||||
|
||||
if goal_phase >= Phase::MakeSpecializations {
|
||||
// Module for deriving is always implicitly loaded into the work graph, but it only
|
||||
// comes into play for make specializations.
|
||||
deps.add_to_status_for_phase(ModuleId::DERIVED_GEN, Phase::MakeSpecializations);
|
||||
}
|
||||
|
||||
deps
|
||||
}
|
||||
|
||||
/// Add all the dependencies for a module, return (module, phase) pairs that can make progress
|
||||
pub fn add_module(
|
||||
&mut self,
|
||||
|
@ -86,24 +157,19 @@ impl<'a> Dependencies<'a> {
|
|||
|
||||
if goal_phase >= MakeSpecializations {
|
||||
self.add_dependency(dep, module_id, Phase::MakeSpecializations);
|
||||
// The module for derives implicitly depends on every other module
|
||||
self.add_dependency(ModuleId::DERIVED_GEN, module_id, Phase::MakeSpecializations);
|
||||
|
||||
let dep_entry = self
|
||||
.make_specializations_dependents
|
||||
.entry(dep)
|
||||
.or_insert((MutSet::default(), false));
|
||||
dep_entry.1 = true;
|
||||
// `dep` depends on `module_id` making specializations first
|
||||
self.make_specializations_dependents.mark_has_pred(dep);
|
||||
}
|
||||
}
|
||||
|
||||
// Add make specialization dependents
|
||||
let entry = self
|
||||
.make_specializations_dependents
|
||||
.entry(module_id)
|
||||
.or_insert((MutSet::default(), false));
|
||||
debug_assert!(entry.0.is_empty(), "already seen this dep");
|
||||
entry
|
||||
.0
|
||||
.extend(dependencies.iter().map(|dep| *dep.as_inner()));
|
||||
if goal_phase >= MakeSpecializations {
|
||||
// Add make specialization dependents
|
||||
self.make_specializations_dependents
|
||||
.add_succ(module_id, dependencies.iter().map(|dep| *dep.as_inner()));
|
||||
}
|
||||
|
||||
// add dependencies for self
|
||||
// phase i + 1 of a file always depends on phase i being completed
|
||||
|
@ -115,20 +181,26 @@ impl<'a> Dependencies<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
self.add_to_status(module_id, goal_phase);
|
||||
self.add_to_status_for_all_phases(module_id, goal_phase);
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
fn add_to_status(&mut self, module_id: ModuleId, goal_phase: Phase) {
|
||||
/// Adds a status for the given module for exactly one phase.
|
||||
fn add_to_status_for_phase(&mut self, module_id: ModuleId, phase: Phase) {
|
||||
if let Entry::Vacant(entry) = self.status.entry(Job::Step(module_id, phase)) {
|
||||
entry.insert(Status::NotStarted);
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a status for the given module for all phases up to and including the goal phase.
|
||||
fn add_to_status_for_all_phases(&mut self, module_id: ModuleId, goal_phase: Phase) {
|
||||
for phase in PHASES.iter() {
|
||||
if *phase > goal_phase {
|
||||
break;
|
||||
}
|
||||
|
||||
if let Entry::Vacant(entry) = self.status.entry(Job::Step(module_id, *phase)) {
|
||||
entry.insert(Status::NotStarted);
|
||||
}
|
||||
self.add_to_status_for_phase(module_id, *phase);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,13 +377,14 @@ impl<'a> Dependencies<'a> {
|
|||
pub fn reload_make_specialization_pass(&mut self) -> MutSet<(ModuleId, Phase)> {
|
||||
let mut output = MutSet::default();
|
||||
|
||||
let mut make_specializations_dependents = Default::default();
|
||||
let mut make_specializations_dependents = MakeSpecializationsDependents::default();
|
||||
let default_make_specializations_dependents_len = make_specializations_dependents.0.len();
|
||||
std::mem::swap(
|
||||
&mut self.make_specializations_dependents,
|
||||
&mut make_specializations_dependents,
|
||||
);
|
||||
|
||||
for (&module, _) in make_specializations_dependents.iter() {
|
||||
for (&module, _) in make_specializations_dependents.0.iter() {
|
||||
let job = Job::Step(module, Phase::MakeSpecializations);
|
||||
let status = self.status.get_mut(&job).unwrap();
|
||||
debug_assert!(
|
||||
|
@ -324,12 +397,14 @@ impl<'a> Dependencies<'a> {
|
|||
// `add_dependency` borrows self as mut so we move `make_specializations_dependents` out
|
||||
// for our local use. `add_dependency` should never grow the make specializations
|
||||
// dependency graph.
|
||||
for (&module, (succ, has_pred)) in make_specializations_dependents.iter() {
|
||||
for (&module, MakeSpecializationInfo { succ, has_pred }) in
|
||||
make_specializations_dependents.0.iter()
|
||||
{
|
||||
for &dependent in succ {
|
||||
self.add_dependency(dependent, module, Phase::MakeSpecializations);
|
||||
}
|
||||
|
||||
self.add_to_status(module, Phase::MakeSpecializations);
|
||||
self.add_to_status_for_phase(module, Phase::MakeSpecializations);
|
||||
if !has_pred {
|
||||
output.insert((module, Phase::MakeSpecializations));
|
||||
}
|
||||
|
@ -339,9 +414,11 @@ impl<'a> Dependencies<'a> {
|
|||
&mut self.make_specializations_dependents,
|
||||
&mut make_specializations_dependents,
|
||||
);
|
||||
debug_assert!(
|
||||
make_specializations_dependents.is_empty(),
|
||||
"more modules were added to the graph"
|
||||
debug_assert_eq!(
|
||||
make_specializations_dependents.0.len(),
|
||||
default_make_specializations_dependents_len,
|
||||
"more modules were added to the graph: {:?}",
|
||||
make_specializations_dependents
|
||||
);
|
||||
|
||||
output
|
||||
|
|
|
@ -35,13 +35,12 @@ use std::path::PathBuf;
|
|||
fn load_and_typecheck(
|
||||
arena: &Bump,
|
||||
filename: PathBuf,
|
||||
src_dir: PathBuf,
|
||||
exposed_types: ExposedByModule,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<LoadedModule, LoadingProblem> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_path(arena, src_dir, filename, RenderTarget::Generic)?;
|
||||
let load_start = LoadStart::from_path(arena, filename, RenderTarget::Generic)?;
|
||||
|
||||
match roc_load_internal::file::load(
|
||||
arena,
|
||||
|
@ -163,13 +162,7 @@ fn multiple_modules_help<'a>(
|
|||
writeln!(file, "{}", source)?;
|
||||
file_handles.push(file);
|
||||
|
||||
load_and_typecheck(
|
||||
arena,
|
||||
full_file_path,
|
||||
dir.path().to_path_buf(),
|
||||
Default::default(),
|
||||
TARGET_INFO,
|
||||
)
|
||||
load_and_typecheck(arena, full_file_path, Default::default(), TARGET_INFO)
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
|
@ -183,7 +176,7 @@ fn load_fixture(
|
|||
let src_dir = fixtures_dir().join(dir_name);
|
||||
let filename = src_dir.join(format!("{}.roc", module_name));
|
||||
let arena = Bump::new();
|
||||
let loaded = load_and_typecheck(&arena, filename, src_dir, subs_by_module, TARGET_INFO);
|
||||
let loaded = load_and_typecheck(&arena, filename, subs_by_module, TARGET_INFO);
|
||||
let mut loaded_module = match loaded {
|
||||
Ok(x) => x,
|
||||
Err(roc_load_internal::file::LoadingProblem::FormattedReport(report)) => {
|
||||
|
@ -339,7 +332,7 @@ fn interface_with_deps() {
|
|||
let src_dir = fixtures_dir().join("interface_with_deps");
|
||||
let filename = src_dir.join("Primary.roc");
|
||||
let arena = Bump::new();
|
||||
let loaded = load_and_typecheck(&arena, filename, src_dir, subs_by_module, TARGET_INFO);
|
||||
let loaded = load_and_typecheck(&arena, filename, subs_by_module, TARGET_INFO);
|
||||
|
||||
let mut loaded_module = loaded.expect("Test module failed to load");
|
||||
let home = loaded_module.module_id;
|
||||
|
|
|
@ -249,7 +249,7 @@ lazy_static! {
|
|||
std::sync::Mutex::new(roc_collections::SmallStringInterner::with_capacity(10));
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Interns {
|
||||
pub module_ids: ModuleIds,
|
||||
pub all_ident_ids: IdentIdsByModule,
|
||||
|
@ -663,7 +663,7 @@ impl IdentIds {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct IdentIdsByModule(VecMap<ModuleId, IdentIds>);
|
||||
|
||||
impl IdentIdsByModule {
|
||||
|
@ -1001,10 +1001,13 @@ define_builtins! {
|
|||
|
||||
31 ATTR_INVALID: "#attr_invalid"
|
||||
}
|
||||
// Fake module for storing derived function symbols
|
||||
1 DERIVED: "#Derived" => {
|
||||
// Fake module for synthesizing and storing derived implementations
|
||||
1 DERIVED_SYNTH: "#Derived" => {
|
||||
}
|
||||
2 NUM: "Num" => {
|
||||
// Fake module from which derived implementations are code-generated
|
||||
2 DERIVED_GEN: "#Derived_gen" => {
|
||||
}
|
||||
3 NUM: "Num" => {
|
||||
0 NUM_NUM: "Num" // the Num.Num type alias
|
||||
1 NUM_I128: "I128" // the Num.I128 type alias
|
||||
2 NUM_U128: "U128" // the Num.U128 type alias
|
||||
|
@ -1152,7 +1155,7 @@ define_builtins! {
|
|||
144 NUM_BYTES_TO_U16_LOWLEVEL: "bytesToU16Lowlevel"
|
||||
145 NUM_BYTES_TO_U32_LOWLEVEL: "bytesToU32Lowlevel"
|
||||
}
|
||||
3 BOOL: "Bool" => {
|
||||
4 BOOL: "Bool" => {
|
||||
0 BOOL_BOOL: "Bool" // the Bool.Bool type alias
|
||||
1 BOOL_FALSE: "False" imported // Bool.Bool = [False, True]
|
||||
// NB: not strictly needed; used for finding tag names in error suggestions
|
||||
|
@ -1165,7 +1168,7 @@ define_builtins! {
|
|||
7 BOOL_EQ: "isEq"
|
||||
8 BOOL_NEQ: "isNotEq"
|
||||
}
|
||||
4 STR: "Str" => {
|
||||
5 STR: "Str" => {
|
||||
0 STR_STR: "Str" imported // the Str.Str type alias
|
||||
1 STR_IS_EMPTY: "isEmpty"
|
||||
2 STR_APPEND: "#append" // unused
|
||||
|
@ -1217,7 +1220,7 @@ define_builtins! {
|
|||
48 STR_FROM_UTF8_RANGE_LOWLEVEL: "fromUtf8RangeLowlevel"
|
||||
49 STR_CAPACITY: "capacity"
|
||||
}
|
||||
5 LIST: "List" => {
|
||||
6 LIST: "List" => {
|
||||
0 LIST_LIST: "List" imported // the List.List type alias
|
||||
1 LIST_IS_EMPTY: "isEmpty"
|
||||
2 LIST_GET: "get"
|
||||
|
@ -1288,7 +1291,7 @@ define_builtins! {
|
|||
67 LIST_SUBLIST_LOWLEVEL: "sublistLowlevel"
|
||||
68 LIST_CAPACITY: "capacity"
|
||||
}
|
||||
6 RESULT: "Result" => {
|
||||
7 RESULT: "Result" => {
|
||||
0 RESULT_RESULT: "Result" // the Result.Result type alias
|
||||
1 RESULT_OK: "Ok" imported // Result.Result a e = [Ok a, Err e]
|
||||
// NB: not strictly needed; used for finding tag names in error suggestions
|
||||
|
@ -1302,7 +1305,7 @@ define_builtins! {
|
|||
8 RESULT_IS_ERR: "isErr"
|
||||
9 RESULT_AFTER_ERR: "afterErr"
|
||||
}
|
||||
7 DICT: "Dict" => {
|
||||
8 DICT: "Dict" => {
|
||||
0 DICT_DICT: "Dict" // the Dict.Dict type alias
|
||||
1 DICT_EMPTY: "empty"
|
||||
2 DICT_SINGLE: "single"
|
||||
|
@ -1324,7 +1327,7 @@ define_builtins! {
|
|||
15 DICT_WITH_CAPACITY: "withCapacity"
|
||||
16 DICT_CAPACITY: "capacity"
|
||||
}
|
||||
8 SET: "Set" => {
|
||||
9 SET: "Set" => {
|
||||
0 SET_SET: "Set" // the Set.Set type alias
|
||||
1 SET_EMPTY: "empty"
|
||||
2 SET_SINGLE: "single"
|
||||
|
@ -1342,12 +1345,12 @@ define_builtins! {
|
|||
14 SET_TO_DICT: "toDict"
|
||||
15 SET_CAPACITY: "capacity"
|
||||
}
|
||||
9 BOX: "Box" => {
|
||||
10 BOX: "Box" => {
|
||||
0 BOX_BOX_TYPE: "Box" imported // the Box.Box opaque type
|
||||
1 BOX_BOX_FUNCTION: "box" // Box.box
|
||||
2 BOX_UNBOX: "unbox"
|
||||
}
|
||||
10 ENCODE: "Encode" => {
|
||||
11 ENCODE: "Encode" => {
|
||||
0 ENCODE_ENCODER: "Encoder"
|
||||
1 ENCODE_ENCODING: "Encoding"
|
||||
2 ENCODE_TO_ENCODER: "toEncoder"
|
||||
|
@ -1375,9 +1378,9 @@ define_builtins! {
|
|||
24 ENCODE_APPEND: "append"
|
||||
25 ENCODE_TO_BYTES: "toBytes"
|
||||
}
|
||||
11 JSON: "Json" => {
|
||||
12 JSON: "Json" => {
|
||||
0 JSON_JSON: "Json"
|
||||
}
|
||||
|
||||
num_modules: 12 // Keep this count up to date by hand! (TODO: see the mut_map! macro for how we could determine this count correctly in the macro)
|
||||
num_modules: 13 // Keep this count up to date by hand! (TODO: see the mut_map! macro for how we could determine this count correctly in the macro)
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ roc_region = { path = "../region" }
|
|||
roc_module = { path = "../module" }
|
||||
roc_types = { path = "../types" }
|
||||
roc_can = { path = "../can" }
|
||||
roc_derive_key = { path = "../derive_key" }
|
||||
roc_derive = { path = "../derive" }
|
||||
roc_late_solve = { path = "../late_solve" }
|
||||
roc_std = { path = "../../roc_std", default-features = false }
|
||||
roc_problem = { path = "../problem" }
|
||||
|
|
|
@ -922,7 +922,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
|||
NumBytesToU32 => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||
StrStartsWith | StrEndsWith => arena.alloc_slice_copy(&[borrowed, borrowed]),
|
||||
StrStartsWithScalar => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||
StrFromUtf8Range => arena.alloc_slice_copy(&[borrowed, irrelevant, irrelevant]),
|
||||
StrFromUtf8Range => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
||||
StrToUtf8 => arena.alloc_slice_copy(&[owned]),
|
||||
StrRepeat => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||
StrFromInt | StrFromFloat => arena.alloc_slice_copy(&[irrelevant]),
|
||||
|
|
|
@ -9,6 +9,7 @@ use bumpalo::Bump;
|
|||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_can::abilities::SpecializationId;
|
||||
use roc_can::expr::{AnnotatedMark, ClosureData, IntValue};
|
||||
use roc_can::module::ExposedByModule;
|
||||
use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap};
|
||||
use roc_collections::VecMap;
|
||||
use roc_debug_flags::dbg_do;
|
||||
|
@ -17,7 +18,7 @@ use roc_debug_flags::{
|
|||
ROC_PRINT_IR_AFTER_REFCOUNT, ROC_PRINT_IR_AFTER_RESET_REUSE, ROC_PRINT_IR_AFTER_SPECIALIZATION,
|
||||
ROC_PRINT_RUNTIME_ERROR_GEN,
|
||||
};
|
||||
use roc_derive_key::GlobalDerivedSymbols;
|
||||
use roc_derive::SharedDerivedModule;
|
||||
use roc_error_macros::{internal_error, todo_abilities};
|
||||
use roc_exhaustive::{Ctor, CtorName, Guard, RenderAs, TagId};
|
||||
use roc_late_solve::{resolve_ability_specialization, AbilitiesView, Resolved, UnificationFailed};
|
||||
|
@ -918,7 +919,7 @@ impl<'a> SymbolSpecializations<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct ProcsBase<'a> {
|
||||
pub partial_procs: BumpMap<Symbol, PartialProc<'a>>,
|
||||
pub module_thunks: &'a [Symbol],
|
||||
|
@ -1293,8 +1294,10 @@ pub struct Env<'a, 'i> {
|
|||
pub target_info: TargetInfo,
|
||||
pub update_mode_ids: &'i mut UpdateModeIds,
|
||||
pub call_specialization_counter: u32,
|
||||
// TODO: WorldAbilities and exposed_by_module share things, think about how to combine them
|
||||
pub abilities: AbilitiesView<'i>,
|
||||
pub derived_symbols: &'i GlobalDerivedSymbols,
|
||||
pub exposed_by_module: &'i ExposedByModule,
|
||||
pub derived_module: &'i SharedDerivedModule,
|
||||
}
|
||||
|
||||
impl<'a, 'i> Env<'a, 'i> {
|
||||
|
@ -1319,18 +1322,43 @@ impl<'a, 'i> Env<'a, 'i> {
|
|||
}
|
||||
|
||||
pub fn is_imported_symbol(&self, symbol: Symbol) -> bool {
|
||||
symbol.module_id() != self.home
|
||||
let sym_module = symbol.module_id();
|
||||
sym_module != self.home
|
||||
// The Derived_gen module takes responsibility for code-generating symbols in the
|
||||
// Derived_synth module.
|
||||
&& !(self.home == ModuleId::DERIVED_GEN && sym_module == ModuleId::DERIVED_SYNTH)
|
||||
}
|
||||
|
||||
/// While specializing the Derived_gen module, derived implementation symbols from the
|
||||
/// Derived_synth module may be discovered. These implementations may not have yet been loaded
|
||||
/// into the Derived_gen module, because we only load them before making specializations, and
|
||||
/// not during mono itself (yet).
|
||||
///
|
||||
/// When this procedure returns `true`, the symbol should be marked as an external specialization,
|
||||
/// so that a subsequent specializations pass loads the derived implementation into Derived_gen
|
||||
/// and then code-generates appropriately.
|
||||
pub fn is_unloaded_derived_symbol(&self, symbol: Symbol, procs: &Procs<'a>) -> bool {
|
||||
self.home == ModuleId::DERIVED_GEN
|
||||
&& symbol.module_id() == ModuleId::DERIVED_SYNTH
|
||||
&& !procs.partial_procs.contains_key(symbol)
|
||||
}
|
||||
|
||||
/// Unifies two variables and performs lambda set compaction.
|
||||
/// Use this rather than [roc_unify::unify] directly!
|
||||
fn unify(&mut self, left: Variable, right: Variable) -> Result<(), UnificationFailed> {
|
||||
debug_assert_ne!(
|
||||
self.home,
|
||||
ModuleId::DERIVED_SYNTH,
|
||||
"should never be monomorphizing the derived synth module!"
|
||||
);
|
||||
|
||||
roc_late_solve::unify(
|
||||
self.home,
|
||||
self.arena,
|
||||
self.subs,
|
||||
&self.abilities,
|
||||
self.derived_symbols,
|
||||
self.derived_module,
|
||||
self.exposed_by_module,
|
||||
left,
|
||||
right,
|
||||
)
|
||||
|
@ -2347,7 +2375,7 @@ fn from_can_let<'a>(
|
|||
for (_specialization_mark, (var, specialized_symbol)) in
|
||||
needed_specializations
|
||||
{
|
||||
use crate::copy::deep_copy_type_vars_into_expr;
|
||||
use roc_can::copy::deep_copy_type_vars_into_expr;
|
||||
|
||||
let (new_def_expr_var, specialized_expr) = deep_copy_type_vars_into_expr(
|
||||
env.subs,
|
||||
|
@ -2625,6 +2653,7 @@ fn specialize_suspended<'a>(
|
|||
None => {
|
||||
// TODO this assumes the specialization is done by another module
|
||||
// make sure this does not become a problem down the road!
|
||||
debug_assert!(name.name().module_id() != name.name().module_id());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -7682,7 +7711,9 @@ fn call_by_name_help<'a>(
|
|||
assigned,
|
||||
hole,
|
||||
)
|
||||
} else if env.is_imported_symbol(proc_name.name()) {
|
||||
} else if env.is_imported_symbol(proc_name.name())
|
||||
|| env.is_unloaded_derived_symbol(proc_name.name(), procs)
|
||||
{
|
||||
add_needed_external(procs, env, original_fn_var, proc_name);
|
||||
|
||||
debug_assert_ne!(proc_name.name().module_id(), ModuleId::ATTR);
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
pub mod borrow;
|
||||
pub mod code_gen_help;
|
||||
mod copy;
|
||||
pub mod inc_dec;
|
||||
pub mod ir;
|
||||
pub mod layout;
|
||||
|
|
|
@ -14,6 +14,7 @@ roc_module = { path = "../module" }
|
|||
roc_types = { path = "../types" }
|
||||
roc_can = { path = "../can" }
|
||||
roc_derive_key = { path = "../derive_key" }
|
||||
roc_derive = { path = "../derive" }
|
||||
roc_problem = { path = "../problem" }
|
||||
roc_unify = { path = "../unify" }
|
||||
roc_debug_flags = { path = "../debug_flags" }
|
||||
|
@ -28,7 +29,7 @@ roc_parse = { path = "../parse" }
|
|||
roc_solve = { path = "../solve" }
|
||||
roc_target = { path = "../roc_target" }
|
||||
roc_reporting = { path = "../../reporting" }
|
||||
roc_derive_key = { path = "../derive_key", features = ["debug-derived-symbols"] }
|
||||
roc_derive = { path = "../derive", features = ["debug-derived-symbols"] }
|
||||
pretty_assertions = "1.0.0"
|
||||
indoc = "1.0.3"
|
||||
tempfile = "3.2.0"
|
||||
|
|
|
@ -55,7 +55,7 @@ pub enum Unfulfilled {
|
|||
},
|
||||
}
|
||||
|
||||
/// Indexes a deriving of an ability for an opaque type.
|
||||
/// Indexes a requested deriving of an ability for an opaque type.
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub struct RequestedDeriveKey {
|
||||
pub opaque: Symbol,
|
||||
|
|
|
@ -2,12 +2,12 @@ use crate::solve::{self, Aliases};
|
|||
use roc_can::abilities::{AbilitiesStore, ResolvedSpecializations};
|
||||
use roc_can::constraint::{Constraint as ConstraintSoa, Constraints};
|
||||
use roc_can::expr::PendingDerives;
|
||||
use roc_can::module::RigidVariables;
|
||||
use roc_can::module::{ExposedByModule, RigidVariables};
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_collections::VecMap;
|
||||
use roc_derive_key::GlobalDerivedSymbols;
|
||||
use roc_derive::SharedDerivedModule;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
use roc_types::subs::{Content, ExposedTypesStorageSubs, FlatType, StorageSubs, Subs, Variable};
|
||||
use roc_types::types::Alias;
|
||||
|
||||
|
@ -54,6 +54,7 @@ pub struct SolvedModule {
|
|||
|
||||
#[allow(clippy::too_many_arguments)] // TODO: put params in a context/env var
|
||||
pub fn run_solve(
|
||||
home: ModuleId,
|
||||
constraints: &Constraints,
|
||||
constraint: ConstraintSoa,
|
||||
rigid_variables: RigidVariables,
|
||||
|
@ -61,7 +62,8 @@ pub fn run_solve(
|
|||
mut aliases: Aliases,
|
||||
mut abilities_store: AbilitiesStore,
|
||||
pending_derives: PendingDerives,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
exposed_by_module: &ExposedByModule,
|
||||
derived_module: SharedDerivedModule,
|
||||
) -> (
|
||||
Solved<Subs>,
|
||||
solve::Env,
|
||||
|
@ -86,6 +88,7 @@ pub fn run_solve(
|
|||
|
||||
// Run the solver to populate Subs.
|
||||
let (solved_subs, solved_env) = solve::run(
|
||||
home,
|
||||
constraints,
|
||||
&mut problems,
|
||||
subs,
|
||||
|
@ -93,7 +96,8 @@ pub fn run_solve(
|
|||
&constraint,
|
||||
pending_derives,
|
||||
&mut abilities_store,
|
||||
derived_symbols,
|
||||
exposed_by_module,
|
||||
derived_module,
|
||||
);
|
||||
|
||||
(solved_subs, solved_env, problems, abilities_store)
|
||||
|
|
|
@ -9,11 +9,13 @@ use roc_can::constraint::Constraint::{self, *};
|
|||
use roc_can::constraint::{Constraints, Cycle, LetConstraint, OpportunisticResolve};
|
||||
use roc_can::expected::{Expected, PExpected};
|
||||
use roc_can::expr::PendingDerives;
|
||||
use roc_can::module::ExposedByModule;
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_debug_flags::dbg_do;
|
||||
#[cfg(debug_assertions)]
|
||||
use roc_debug_flags::{ROC_TRACE_COMPACTION, ROC_VERIFY_RIGID_LET_GENERALIZED};
|
||||
use roc_derive_key::{DeriveError, Derived, GlobalDerivedSymbols};
|
||||
use roc_derive::SharedDerivedModule;
|
||||
use roc_derive_key::{DeriveError, DeriveKey};
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::ident::TagName;
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
|
@ -580,6 +582,7 @@ struct State {
|
|||
|
||||
#[allow(clippy::too_many_arguments)] // TODO: put params in a context/env var
|
||||
pub fn run(
|
||||
home: ModuleId,
|
||||
constraints: &Constraints,
|
||||
problems: &mut Vec<TypeError>,
|
||||
mut subs: Subs,
|
||||
|
@ -587,9 +590,11 @@ pub fn run(
|
|||
constraint: &Constraint,
|
||||
pending_derives: PendingDerives,
|
||||
abilities_store: &mut AbilitiesStore,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
exposed_by_module: &ExposedByModule,
|
||||
derived_module: SharedDerivedModule,
|
||||
) -> (Solved<Subs>, Env) {
|
||||
let env = run_in_place(
|
||||
home,
|
||||
constraints,
|
||||
problems,
|
||||
&mut subs,
|
||||
|
@ -597,7 +602,8 @@ pub fn run(
|
|||
constraint,
|
||||
pending_derives,
|
||||
abilities_store,
|
||||
derived_symbols,
|
||||
exposed_by_module,
|
||||
derived_module,
|
||||
);
|
||||
|
||||
(Solved(subs), env)
|
||||
|
@ -606,6 +612,7 @@ pub fn run(
|
|||
/// Modify an existing subs in-place instead
|
||||
#[allow(clippy::too_many_arguments)] // TODO: put params in a context/env var
|
||||
fn run_in_place(
|
||||
_home: ModuleId, // TODO: remove me?
|
||||
constraints: &Constraints,
|
||||
problems: &mut Vec<TypeError>,
|
||||
subs: &mut Subs,
|
||||
|
@ -613,7 +620,8 @@ fn run_in_place(
|
|||
constraint: &Constraint,
|
||||
pending_derives: PendingDerives,
|
||||
abilities_store: &mut AbilitiesStore,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
exposed_by_module: &ExposedByModule,
|
||||
derived_module: SharedDerivedModule,
|
||||
) -> Env {
|
||||
let mut pools = Pools::default();
|
||||
|
||||
|
@ -651,11 +659,12 @@ fn run_in_place(
|
|||
// are legal, which we need to register.
|
||||
let new_must_implement = compact_lambda_sets_of_vars(
|
||||
subs,
|
||||
&derived_module,
|
||||
&arena,
|
||||
&mut pools,
|
||||
deferred_uls_to_resolve,
|
||||
&SolvePhase { abilities_store },
|
||||
&derived_symbols,
|
||||
exposed_by_module,
|
||||
);
|
||||
|
||||
deferred_obligations.add(new_must_implement, AbilityImplError::IncompleteAbility);
|
||||
|
@ -1913,11 +1922,12 @@ fn unique_unspecialized_lambda(subs: &Subs, c_a: Variable, uls: &[Uls]) -> Optio
|
|||
#[must_use]
|
||||
pub fn compact_lambda_sets_of_vars<P: Phase>(
|
||||
subs: &mut Subs,
|
||||
derived_module: &SharedDerivedModule,
|
||||
arena: &Bump,
|
||||
pools: &mut Pools,
|
||||
uls_of_var: UlsOfVar,
|
||||
phase: &P,
|
||||
derived_symbols: &GlobalDerivedSymbols,
|
||||
exposed_by_module: &ExposedByModule,
|
||||
) -> MustImplementConstraints {
|
||||
// let mut seen = VecSet::default();
|
||||
let mut must_implement = MustImplementConstraints::default();
|
||||
|
@ -2026,6 +2036,7 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
|||
ord => ord,
|
||||
}
|
||||
});
|
||||
|
||||
trace_compact!(2. subs, &uls_a);
|
||||
|
||||
// 3. For each `l` in `uls_a` with unique unspecialized lambda `C:f:r`:
|
||||
|
@ -2041,8 +2052,16 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
|||
// continue;
|
||||
// }
|
||||
|
||||
let (new_must_implement, new_uls_of_var) =
|
||||
compact_lambda_set(subs, arena, pools, c_a, l, phase, derived_symbols);
|
||||
let (new_must_implement, new_uls_of_var) = compact_lambda_set(
|
||||
subs,
|
||||
derived_module,
|
||||
arena,
|
||||
pools,
|
||||
c_a,
|
||||
l,
|
||||
phase,
|
||||
exposed_by_module,
|
||||
);
|
||||
|
||||
must_implement.extend(new_must_implement);
|
||||
uls_of_var_queue.extend(new_uls_of_var.drain());
|
||||
|
@ -2055,14 +2074,16 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn compact_lambda_set<P: Phase>(
|
||||
subs: &mut Subs,
|
||||
derived_module: &SharedDerivedModule,
|
||||
arena: &Bump,
|
||||
pools: &mut Pools,
|
||||
resolved_concrete: Variable,
|
||||
this_lambda_set: Variable,
|
||||
phase: &P,
|
||||
derived_symbols: &GlobalDerivedSymbols,
|
||||
exposed_by_module: &ExposedByModule,
|
||||
) -> (MustImplementConstraints, UlsOfVar) {
|
||||
// 3. For each `l` in `uls_a` with unique unspecialized lambda `C:f:r`:
|
||||
// 1. Let `t_f1` be the directly ambient function of the lambda set containing `C:f:r`. Remove `C:f:r` from `t_f1`'s lambda set.
|
||||
|
@ -2108,143 +2129,172 @@ fn compact_lambda_set<P: Phase>(
|
|||
Content::LambdaSet(t_f1_lambda_set_without_concrete),
|
||||
);
|
||||
|
||||
enum Spec {
|
||||
// 2. Let `t_f2` be the directly ambient function of the specialization lambda set resolved by `C:f:r`.
|
||||
Some { t_f2: Variable },
|
||||
// The specialized lambda set should actually just be dropped, not resolved and unified.
|
||||
Drop,
|
||||
}
|
||||
let specialization_decision = make_specialization_decision(subs, c);
|
||||
|
||||
let spec = match subs.get_content_without_compacting(c) {
|
||||
Content::Structure(_) | Content::Alias(_, _, _, AliasKind::Structural) => {
|
||||
let specialization_key = match specialization_decision {
|
||||
SpecializeDecision::Specialize(key) => key,
|
||||
SpecializeDecision::Drop => {
|
||||
// Do nothing other than to remove the concrete lambda to drop from the lambda set,
|
||||
// which we already did in 1b above.
|
||||
trace_compact!(3iter_end_skipped. subs, t_f1);
|
||||
return (Default::default(), Default::default());
|
||||
}
|
||||
};
|
||||
|
||||
let specialization_ambient_function_var = get_specialization_lambda_set_ambient_function(
|
||||
subs,
|
||||
derived_module,
|
||||
phase,
|
||||
f,
|
||||
r,
|
||||
specialization_key,
|
||||
exposed_by_module,
|
||||
target_rank,
|
||||
);
|
||||
|
||||
let t_f2 = match specialization_ambient_function_var {
|
||||
Ok(lset) => lset,
|
||||
Err(()) => {
|
||||
// Do nothing other than to remove the concrete lambda to drop from the lambda set,
|
||||
// which we already did in 1b above.
|
||||
trace_compact!(3iter_end_skipped. subs, t_f1);
|
||||
return (Default::default(), Default::default());
|
||||
}
|
||||
};
|
||||
|
||||
// Ensure the specialized ambient function we'll unify with is not a generalized one, but one
|
||||
// at the rank of the lambda set being compacted.
|
||||
let t_f2 = deep_copy_var_in(subs, target_rank, pools, t_f2, arena);
|
||||
|
||||
// 3. Unify `t_f1 ~ t_f2`.
|
||||
trace_compact!(3iter_start. subs, this_lambda_set, t_f1, t_f2);
|
||||
let (vars, new_must_implement_ability, new_lambda_sets_to_specialize, _meta) =
|
||||
unify(subs, t_f1, t_f2, Mode::EQ).expect_success("ambient functions don't unify");
|
||||
trace_compact!(3iter_end. subs, t_f1);
|
||||
|
||||
introduce(subs, target_rank, pools, &vars);
|
||||
|
||||
(new_must_implement_ability, new_lambda_sets_to_specialize)
|
||||
}
|
||||
|
||||
enum SpecializationTypeKey {
|
||||
Opaque(Symbol),
|
||||
Derived(DeriveKey),
|
||||
}
|
||||
|
||||
enum SpecializeDecision {
|
||||
Specialize(SpecializationTypeKey),
|
||||
Drop,
|
||||
}
|
||||
|
||||
fn make_specialization_decision(subs: &Subs, var: Variable) -> SpecializeDecision {
|
||||
use Content::*;
|
||||
use SpecializationTypeKey::*;
|
||||
match subs.get_content_without_compacting(var) {
|
||||
Structure(_) | Alias(_, _, _, AliasKind::Structural) => {
|
||||
// This is a structural type, find the name of the derived ability function it
|
||||
// should use.
|
||||
match Derived::encoding(subs, c) {
|
||||
Ok(derived) => {
|
||||
let specialization_symbol = match derived {
|
||||
Derived::Immediate(symbol) => symbol,
|
||||
Derived::Key(derive_key) => {
|
||||
let mut derived_symbols = derived_symbols.lock().unwrap();
|
||||
derived_symbols.get_or_insert(derive_key)
|
||||
}
|
||||
};
|
||||
|
||||
let specialization_symbol_slice =
|
||||
UnionLabels::insert_into_subs(subs, vec![(specialization_symbol, vec![])]);
|
||||
// TODO: This is WRONG, fix it!
|
||||
let ambient_function = Variable::NULL;
|
||||
let _lambda_set_for_derived = subs.fresh(Descriptor {
|
||||
content: Content::LambdaSet(subs::LambdaSet {
|
||||
solved: specialization_symbol_slice,
|
||||
recursion_var: OptVariable::NONE,
|
||||
unspecialized: SubsSlice::default(),
|
||||
ambient_function,
|
||||
}),
|
||||
rank: target_rank,
|
||||
mark: Mark::NONE,
|
||||
copy: OptVariable::NONE,
|
||||
});
|
||||
|
||||
Spec::Some {
|
||||
t_f2: ambient_function,
|
||||
match roc_derive_key::Derived::encoding(subs, var) {
|
||||
Ok(derived) => match derived {
|
||||
roc_derive_key::Derived::Immediate(_) => {
|
||||
todo!("deal with lambda set extraction from immediates")
|
||||
}
|
||||
}
|
||||
roc_derive_key::Derived::Key(derive_key) => {
|
||||
SpecializeDecision::Specialize(Derived(derive_key))
|
||||
}
|
||||
},
|
||||
Err(DeriveError::UnboundVar) => {
|
||||
// not specialized yet, but that also means that it can't possibly be derivable
|
||||
// at this point?
|
||||
// TODO: is this right? Revisit if it causes us problems in the future.
|
||||
Spec::Drop
|
||||
SpecializeDecision::Drop
|
||||
}
|
||||
Err(DeriveError::Underivable) => {
|
||||
// we should have reported an error for this; drop the lambda set.
|
||||
Spec::Drop
|
||||
SpecializeDecision::Drop
|
||||
}
|
||||
}
|
||||
}
|
||||
Content::Alias(opaque, _, _, AliasKind::Opaque) => {
|
||||
Alias(opaque, _, _, AliasKind::Opaque) => SpecializeDecision::Specialize(Opaque(*opaque)),
|
||||
Error => SpecializeDecision::Drop,
|
||||
FlexAbleVar(_, _)
|
||||
| RigidAbleVar(..)
|
||||
| FlexVar(..)
|
||||
| RigidVar(..)
|
||||
| RecursionVar { .. }
|
||||
| LambdaSet(..)
|
||||
| RangedNumber(..) => {
|
||||
internal_error!("unexpected")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn get_specialization_lambda_set_ambient_function<P: Phase>(
|
||||
subs: &mut Subs,
|
||||
derived_module: &SharedDerivedModule,
|
||||
phase: &P,
|
||||
ability_member: Symbol,
|
||||
lset_region: u8,
|
||||
specialization_key: SpecializationTypeKey,
|
||||
exposed_by_module: &ExposedByModule,
|
||||
target_rank: Rank,
|
||||
) -> Result<Variable, ()> {
|
||||
match specialization_key {
|
||||
SpecializationTypeKey::Opaque(opaque) => {
|
||||
let opaque_home = opaque.module_id();
|
||||
let opt_lambda_set =
|
||||
let external_specialized_lset =
|
||||
phase.with_module_abilities_store(opaque_home, |abilities_store| {
|
||||
let opt_specialization = abilities_store.get_specialization(f, *opaque);
|
||||
let opt_specialization =
|
||||
abilities_store.get_specialization(ability_member, opaque);
|
||||
match (P::IS_LATE, opt_specialization) {
|
||||
(false, None) => {
|
||||
// doesn't specialize, we'll have reported an error for this
|
||||
None
|
||||
Err(())
|
||||
}
|
||||
(true, None) => {
|
||||
internal_error!(
|
||||
"expected to know a specialization for {:?}#{:?}, but it wasn't found",
|
||||
opaque,
|
||||
f,
|
||||
ability_member,
|
||||
);
|
||||
}
|
||||
(_, Some(specialization)) => {
|
||||
let specialized_lambda_set = *specialization
|
||||
.specialization_lambda_sets
|
||||
.get(&r)
|
||||
.unwrap_or_else(|| {
|
||||
internal_error!(
|
||||
"lambda set region ({:?}, {}) not resolved",
|
||||
f,
|
||||
r
|
||||
)
|
||||
});
|
||||
Some(specialized_lambda_set)
|
||||
.get(&lset_region)
|
||||
.expect("lambda set region not resolved");
|
||||
Ok(specialized_lambda_set)
|
||||
}
|
||||
}
|
||||
});
|
||||
match opt_lambda_set {
|
||||
Some(lambda_set_var) => {
|
||||
// Get the ambient function type
|
||||
let spec_ambient_function = phase
|
||||
.copy_lambda_set_ambient_function_to_home_subs(
|
||||
lambda_set_var,
|
||||
opaque_home,
|
||||
subs,
|
||||
);
|
||||
})?;
|
||||
|
||||
Spec::Some {
|
||||
t_f2: spec_ambient_function,
|
||||
}
|
||||
}
|
||||
None => Spec::Drop,
|
||||
}
|
||||
let specialized_ambient = phase.copy_lambda_set_ambient_function_to_home_subs(
|
||||
external_specialized_lset,
|
||||
opaque_home,
|
||||
subs,
|
||||
);
|
||||
|
||||
Ok(specialized_ambient)
|
||||
}
|
||||
|
||||
Content::Error => Spec::Drop,
|
||||
SpecializationTypeKey::Derived(derive_key) => {
|
||||
let mut derived_module = derived_module.lock().unwrap();
|
||||
|
||||
Content::FlexAbleVar(..)
|
||||
| Content::RigidAbleVar(..)
|
||||
| Content::FlexVar(..)
|
||||
| Content::RigidVar(..)
|
||||
| Content::RecursionVar { .. }
|
||||
| Content::LambdaSet(..)
|
||||
| Content::RangedNumber(..) => {
|
||||
internal_error!("unexpected")
|
||||
}
|
||||
};
|
||||
let (_, _, specialization_lambda_sets) =
|
||||
derived_module.get_or_insert(exposed_by_module, derive_key);
|
||||
|
||||
match spec {
|
||||
Spec::Some { t_f2 } => {
|
||||
// Ensure the specialized ambient function we'll unify with is not a generalized one, but one
|
||||
// at the rank of the lambda set being compacted.
|
||||
let t_f2 = deep_copy_var_in(subs, target_rank, pools, t_f2, arena);
|
||||
let specialized_lambda_set = *specialization_lambda_sets
|
||||
.get(&lset_region)
|
||||
.expect("lambda set region not resolved");
|
||||
|
||||
// 3. Unify `t_f1 ~ t_f2`.
|
||||
trace_compact!(3iter_start. subs, this_lambda_set, t_f1, t_f2);
|
||||
let (vars, new_must_implement_ability, new_lambda_sets_to_specialize, _meta) =
|
||||
unify(subs, t_f1, t_f2, Mode::EQ).expect_success("ambient functions don't unify");
|
||||
trace_compact!(3iter_end. subs, t_f1);
|
||||
let specialized_ambient = derived_module.copy_lambda_set_ambient_function_to_subs(
|
||||
specialized_lambda_set,
|
||||
subs,
|
||||
target_rank,
|
||||
);
|
||||
|
||||
introduce(subs, target_rank, pools, &vars);
|
||||
|
||||
(new_must_implement_ability, new_lambda_sets_to_specialize)
|
||||
}
|
||||
Spec::Drop => {
|
||||
// Do nothing other than to remove the concrete lambda to drop from the lambda set,
|
||||
// which we already did in 1b above.
|
||||
trace_compact!(3iter_end_skipped. subs, t_f1);
|
||||
(Default::default(), Default::default())
|
||||
Ok(specialized_ambient)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,12 +22,12 @@ use roc_can::{
|
|||
use roc_collections::VecSet;
|
||||
use roc_constrain::expr::constrain_decls;
|
||||
use roc_debug_flags::dbg_do;
|
||||
use roc_derive::{synth_var, DerivedModule, StolenFromDerived};
|
||||
use roc_derive::{synth_var, DerivedModule};
|
||||
use roc_derive_key::{DeriveKey, Derived};
|
||||
use roc_load_internal::file::{add_imports, default_aliases, LoadedModule, Threading};
|
||||
use roc_module::{
|
||||
ident::TagName,
|
||||
symbol::{Interns, ModuleId, Symbol},
|
||||
symbol::{IdentIds, Interns, ModuleId, Symbol},
|
||||
};
|
||||
use roc_region::all::LineInfo;
|
||||
use roc_reporting::report::{type_problem, RocDocAllocator};
|
||||
|
@ -40,7 +40,7 @@ use roc_types::{
|
|||
types::{AliasKind, RecordField},
|
||||
};
|
||||
|
||||
const DERIVED_MODULE: ModuleId = ModuleId::DERIVED;
|
||||
const DERIVED_MODULE: ModuleId = ModuleId::DERIVED_SYNTH;
|
||||
|
||||
fn encode_path() -> PathBuf {
|
||||
let repo_root = std::env::var("ROC_WORKSPACE_DIR").expect("are you running with `cargo test`?");
|
||||
|
@ -145,7 +145,7 @@ fn check_derived_typechecks_and_golden(
|
|||
test_module,
|
||||
&mut test_subs,
|
||||
pending_abilities,
|
||||
exposed_for_module,
|
||||
&exposed_for_module,
|
||||
&mut def_types,
|
||||
&mut rigid_vars,
|
||||
);
|
||||
|
@ -158,6 +158,7 @@ fn check_derived_typechecks_and_golden(
|
|||
std::env::set_var(roc_debug_flags::ROC_PRINT_UNIFICATIONS_DERIVED, "1")
|
||||
);
|
||||
let (mut solved_subs, _, problems, _) = roc_solve::module::run_solve(
|
||||
test_module,
|
||||
&constraints,
|
||||
constr,
|
||||
RigidVariables::default(),
|
||||
|
@ -165,6 +166,7 @@ fn check_derived_typechecks_and_golden(
|
|||
default_aliases(),
|
||||
abilities_store,
|
||||
Default::default(),
|
||||
&exposed_for_module.exposed_by_module,
|
||||
Default::default(),
|
||||
);
|
||||
let subs = solved_subs.inner_mut();
|
||||
|
@ -242,12 +244,12 @@ where
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let mut derived_module = DerivedModule::default();
|
||||
let mut subs = Subs::new();
|
||||
let ident_ids = IdentIds::default();
|
||||
let source_var = synth_input(&mut subs);
|
||||
let key = get_key(&subs, source_var);
|
||||
|
||||
let mut stolen = derived_module.steal();
|
||||
let source_var = synth_input(&mut stolen.subs);
|
||||
let key = get_key(&stolen.subs, source_var);
|
||||
derived_module.return_stolen(stolen);
|
||||
let mut derived_module = unsafe { DerivedModule::from_components(subs, ident_ids) };
|
||||
|
||||
let mut exposed_by_module = ExposedByModule::default();
|
||||
exposed_by_module.insert(
|
||||
|
@ -263,7 +265,7 @@ where
|
|||
let specialization_lsets = specialization_lsets.clone();
|
||||
let derived_def = derived_def.clone();
|
||||
|
||||
let StolenFromDerived { ident_ids, subs } = derived_module.steal();
|
||||
let (subs, ident_ids) = derived_module.decompose();
|
||||
|
||||
interns.all_ident_ids.insert(DERIVED_MODULE, ident_ids);
|
||||
DERIVED_MODULE.register_debug_idents(interns.all_ident_ids.get(&DERIVED_MODULE).unwrap());
|
||||
|
|
|
@ -375,3 +375,122 @@ fn encode_use_stdlib_without_wrapping_custom() {
|
|||
RocStr
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn to_encoder_encode_custom_has_capture() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test"
|
||||
imports [Encode.{ toEncoder }, Json]
|
||||
provides [main] to "./platform"
|
||||
|
||||
HelloWorld := Str
|
||||
toEncoder = \@HelloWorld s1 ->
|
||||
Encode.custom \bytes, fmt ->
|
||||
bytes
|
||||
|> Encode.appendWith (Encode.string s1) fmt
|
||||
|
||||
main =
|
||||
result = Str.fromUtf8 (Encode.toBytes (@HelloWorld "Hello, World!\n") Json.format)
|
||||
when result is
|
||||
Ok s -> s
|
||||
_ -> "<bad>"
|
||||
"#
|
||||
),
|
||||
RocStr::from("\"Hello, World!\n\""),
|
||||
RocStr
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn encode_derived_string() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test"
|
||||
imports [Encode.{ toEncoder }, Json]
|
||||
provides [main] to "./platform"
|
||||
|
||||
main =
|
||||
result = Str.fromUtf8 (Encode.toBytes "foo" Json.format)
|
||||
when result is
|
||||
Ok s -> s
|
||||
_ -> "<bad>"
|
||||
"#
|
||||
),
|
||||
RocStr::from("\"foo\""),
|
||||
RocStr
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn encode_derived_record_one_field_string() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test"
|
||||
imports [Encode.{ toEncoder }, Json]
|
||||
provides [main] to "./platform"
|
||||
|
||||
main =
|
||||
result = Str.fromUtf8 (Encode.toBytes {a: "foo"} Json.format)
|
||||
when result is
|
||||
Ok s -> s
|
||||
_ -> "<bad>"
|
||||
"#
|
||||
),
|
||||
RocStr::from(r#"{"a":"foo",}"#),
|
||||
RocStr
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn encode_derived_record_two_fields_strings() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test"
|
||||
imports [Encode.{ toEncoder }, Json]
|
||||
provides [main] to "./platform"
|
||||
|
||||
main =
|
||||
rcd = {a: "foo", b: "bar"}
|
||||
result = Str.fromUtf8 (Encode.toBytes rcd Json.format)
|
||||
when result is
|
||||
Ok s -> s
|
||||
_ -> "<bad>"
|
||||
"#
|
||||
),
|
||||
RocStr::from(r#"{"a":"foo","b":"bar",}"#),
|
||||
RocStr
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn encode_derived_nested_record_string() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test"
|
||||
imports [Encode.{ toEncoder }, Json]
|
||||
provides [main] to "./platform"
|
||||
|
||||
main =
|
||||
rcd = {a: {b: "bar"}}
|
||||
encoded = Encode.toBytes rcd Json.format
|
||||
result = Str.fromUtf8 encoded
|
||||
when result is
|
||||
Ok s -> s
|
||||
_ -> "<bad>"
|
||||
"#
|
||||
),
|
||||
RocStr::from(r#"{"a":{"b":"bar",},}"#),
|
||||
RocStr
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3054,6 +3054,78 @@ fn num_to_str_i64() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn num_to_str_f32() {
|
||||
use roc_std::RocStr;
|
||||
|
||||
assert_evals_to!(r#"Num.toStr -10.75f32"#, RocStr::from("-10.75"), RocStr);
|
||||
assert_evals_to!(r#"Num.toStr -1.75f32"#, RocStr::from("-1.75"), RocStr);
|
||||
assert_evals_to!(r#"Num.toStr 0f32"#, RocStr::from("0"), RocStr);
|
||||
assert_evals_to!(r#"Num.toStr 1.75f32"#, RocStr::from("1.75"), RocStr);
|
||||
assert_evals_to!(r#"Num.toStr 10.75f32"#, RocStr::from("10.75"), RocStr);
|
||||
|
||||
assert_evals_to!(
|
||||
r#"Num.toStr Num.maxF32"#,
|
||||
RocStr::from("340282346638528860000000000000000000000"),
|
||||
RocStr
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
r#"Num.toStr Num.minF32"#,
|
||||
RocStr::from("-340282346638528860000000000000000000000"),
|
||||
RocStr
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn num_to_str_f64() {
|
||||
use roc_std::RocStr;
|
||||
|
||||
assert_evals_to!(r#"Num.toStr -10.75f64"#, RocStr::from("-10.75"), RocStr);
|
||||
assert_evals_to!(r#"Num.toStr -1.75f64"#, RocStr::from("-1.75"), RocStr);
|
||||
assert_evals_to!(r#"Num.toStr 0f64"#, RocStr::from("0"), RocStr);
|
||||
assert_evals_to!(r#"Num.toStr 1.75f64"#, RocStr::from("1.75"), RocStr);
|
||||
assert_evals_to!(r#"Num.toStr 10.75f64"#, RocStr::from("10.75"), RocStr);
|
||||
|
||||
assert_evals_to!(
|
||||
r#"Num.toStr Num.maxF64"#,
|
||||
RocStr::from(f64::MAX.to_string().as_str()),
|
||||
RocStr
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
r#"Num.toStr Num.minF64"#,
|
||||
RocStr::from(f64::MIN.to_string().as_str()),
|
||||
RocStr
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn num_to_str_dec() {
|
||||
use roc_std::RocStr;
|
||||
|
||||
assert_evals_to!(r#"Num.toStr -10.75dec"#, RocStr::from("-10.75"), RocStr);
|
||||
assert_evals_to!(r#"Num.toStr -1.75dec"#, RocStr::from("-1.75"), RocStr);
|
||||
assert_evals_to!(r#"Num.toStr 0dec"#, RocStr::from("0.0"), RocStr);
|
||||
assert_evals_to!(r#"Num.toStr 1.75dec"#, RocStr::from("1.75"), RocStr);
|
||||
assert_evals_to!(r#"Num.toStr 10.75dec"#, RocStr::from("10.75"), RocStr);
|
||||
|
||||
assert_evals_to!(
|
||||
r#"Num.toStr 170141183460469.105727dec"#,
|
||||
RocStr::from("170141183460469.105727"),
|
||||
RocStr
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
r#"Num.toStr -170141183460469.105727dec"#,
|
||||
RocStr::from("-170141183460469.105727"),
|
||||
RocStr
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn u8_addition_greater_than_i8() {
|
||||
|
|
|
@ -0,0 +1,465 @@
|
|||
procedure #Derived.0 (#Derived.1):
|
||||
let #Derived_gen.1 : {Str} = Struct {#Derived.1};
|
||||
let #Derived_gen.0 : {Str} = CallByName Encode.22 #Derived_gen.1;
|
||||
ret #Derived_gen.0;
|
||||
|
||||
procedure #Derived.10 (#Derived.11):
|
||||
let #Derived_gen.29 : {Str} = Struct {#Derived.11};
|
||||
let #Derived_gen.28 : {Str} = CallByName Encode.22 #Derived_gen.29;
|
||||
ret #Derived_gen.28;
|
||||
|
||||
procedure #Derived.12 (#Derived.13, #Derived.14, #Attr.12):
|
||||
let #Derived.11 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc #Derived.11;
|
||||
dec #Attr.12;
|
||||
let #Derived_gen.32 : {Str} = CallByName Json.17 #Derived.11;
|
||||
let #Derived_gen.31 : List U8 = CallByName Encode.23 #Derived.13 #Derived_gen.32 #Derived.14;
|
||||
ret #Derived_gen.31;
|
||||
|
||||
procedure #Derived.2 (#Derived.3, #Derived.4, #Attr.12):
|
||||
let #Derived.1 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc #Derived.1;
|
||||
dec #Attr.12;
|
||||
let #Derived_gen.7 : Str = "a";
|
||||
let #Derived_gen.8 : {Str} = CallByName #Derived.5 #Derived.1;
|
||||
let #Derived_gen.6 : {Str, {Str}} = Struct {#Derived_gen.7, #Derived_gen.8};
|
||||
let #Derived_gen.5 : List {Str, {Str}} = Array [#Derived_gen.6];
|
||||
let #Derived_gen.4 : {List {Str, {Str}}} = CallByName Json.19 #Derived_gen.5;
|
||||
let #Derived_gen.3 : List U8 = CallByName Encode.23 #Derived.3 #Derived_gen.4 #Derived.4;
|
||||
ret #Derived_gen.3;
|
||||
|
||||
procedure #Derived.5 (#Derived.6):
|
||||
let #Derived_gen.15 : {Str} = Struct {#Derived.6};
|
||||
let #Derived_gen.14 : {Str} = CallByName Encode.22 #Derived_gen.15;
|
||||
ret #Derived_gen.14;
|
||||
|
||||
procedure #Derived.7 (#Derived.8, #Derived.9, #Attr.12):
|
||||
let #Derived.6 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc #Derived.6;
|
||||
dec #Attr.12;
|
||||
let #Derived_gen.21 : Str = "b";
|
||||
let #Derived_gen.22 : {Str} = CallByName #Derived.10 #Derived.6;
|
||||
let #Derived_gen.20 : {Str, {Str}} = Struct {#Derived_gen.21, #Derived_gen.22};
|
||||
let #Derived_gen.19 : List {Str, {Str}} = Array [#Derived_gen.20];
|
||||
let #Derived_gen.18 : {List {Str, {Str}}} = CallByName Json.19 #Derived_gen.19;
|
||||
let #Derived_gen.17 : List U8 = CallByName Encode.23 #Derived.8 #Derived_gen.18 #Derived.9;
|
||||
ret #Derived_gen.17;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.106 : List U8 = CallByName #Derived.2 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.106;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.113 : List U8 = CallByName Json.77 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.113;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.115 : List U8 = CallByName #Derived.7 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.115;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.125 : List U8 = CallByName Json.77 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.125;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.127 : List U8 = CallByName #Derived.12 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.127;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.137 : List U8 = CallByName Json.65 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.137;
|
||||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
let Encode.104 : List U8 = Array [];
|
||||
let Encode.105 : {Str} = CallByName #Derived.0 Encode.100;
|
||||
let Encode.103 : List U8 = CallByName Encode.23 Encode.104 Encode.105 Encode.101;
|
||||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.102 : {} = Struct {};
|
||||
ret Json.102;
|
||||
|
||||
procedure Json.17 (Json.64):
|
||||
let Json.186 : {Str} = Struct {Json.64};
|
||||
let Json.185 : {Str} = CallByName Encode.22 Json.186;
|
||||
ret Json.185;
|
||||
|
||||
procedure Json.19 (Json.76):
|
||||
let Json.104 : {List {Str, {Str}}} = Struct {Json.76};
|
||||
let Json.103 : {List {Str, {Str}}} = CallByName Encode.22 Json.104;
|
||||
ret Json.103;
|
||||
|
||||
procedure Json.19 (Json.76):
|
||||
let Json.146 : {List {Str, {Str}}} = Struct {Json.76};
|
||||
let Json.145 : {List {Str, {Str}}} = CallByName Encode.22 Json.146;
|
||||
ret Json.145;
|
||||
|
||||
procedure Json.65 (Json.66, Json.187, #Attr.12):
|
||||
let Json.64 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.64;
|
||||
dec #Attr.12;
|
||||
let Json.196 : I32 = 34i64;
|
||||
let Json.195 : U8 = CallByName Num.123 Json.196;
|
||||
let Json.193 : List U8 = CallByName List.4 Json.66 Json.195;
|
||||
let Json.194 : List U8 = CallByName Str.12 Json.64;
|
||||
let Json.190 : List U8 = CallByName List.8 Json.193 Json.194;
|
||||
let Json.192 : I32 = 34i64;
|
||||
let Json.191 : U8 = CallByName Num.123 Json.192;
|
||||
let Json.189 : List U8 = CallByName List.4 Json.190 Json.191;
|
||||
ret Json.189;
|
||||
|
||||
procedure Json.77 (Json.78, Json.105, #Attr.12):
|
||||
let Json.76 : List {Str, {Str}} = StructAtIndex 0 #Attr.12;
|
||||
inc Json.76;
|
||||
dec #Attr.12;
|
||||
let Json.138 : I32 = 123i64;
|
||||
let Json.137 : U8 = CallByName Num.123 Json.138;
|
||||
let Json.80 : List U8 = CallByName List.4 Json.78 Json.137;
|
||||
let Json.136 : U64 = CallByName List.6 Json.76;
|
||||
let Json.113 : {List U8, U64} = Struct {Json.80, Json.136};
|
||||
let Json.114 : {} = Struct {};
|
||||
let Json.112 : {List U8, U64} = CallByName List.18 Json.76 Json.113 Json.114;
|
||||
dec Json.76;
|
||||
let Json.82 : List U8 = StructAtIndex 0 Json.112;
|
||||
inc Json.82;
|
||||
dec Json.112;
|
||||
let Json.111 : I32 = 125i64;
|
||||
let Json.110 : U8 = CallByName Num.123 Json.111;
|
||||
let Json.109 : List U8 = CallByName List.4 Json.82 Json.110;
|
||||
ret Json.109;
|
||||
|
||||
procedure Json.77 (Json.78, Json.105, #Attr.12):
|
||||
let Json.76 : List {Str, {Str}} = StructAtIndex 0 #Attr.12;
|
||||
inc Json.76;
|
||||
dec #Attr.12;
|
||||
let Json.178 : I32 = 123i64;
|
||||
let Json.177 : U8 = CallByName Num.123 Json.178;
|
||||
let Json.80 : List U8 = CallByName List.4 Json.78 Json.177;
|
||||
let Json.176 : U64 = CallByName List.6 Json.76;
|
||||
let Json.153 : {List U8, U64} = Struct {Json.80, Json.176};
|
||||
let Json.154 : {} = Struct {};
|
||||
let Json.152 : {List U8, U64} = CallByName List.18 Json.76 Json.153 Json.154;
|
||||
dec Json.76;
|
||||
let Json.82 : List U8 = StructAtIndex 0 Json.152;
|
||||
inc Json.82;
|
||||
dec Json.152;
|
||||
let Json.151 : I32 = 125i64;
|
||||
let Json.150 : U8 = CallByName Num.123 Json.151;
|
||||
let Json.149 : List U8 = CallByName List.4 Json.82 Json.150;
|
||||
ret Json.149;
|
||||
|
||||
procedure Json.79 (Json.107, Json.108):
|
||||
let Json.85 : Str = StructAtIndex 0 Json.108;
|
||||
inc Json.85;
|
||||
let Json.86 : {Str} = StructAtIndex 1 Json.108;
|
||||
inc Json.86;
|
||||
dec Json.108;
|
||||
let Json.83 : List U8 = StructAtIndex 0 Json.107;
|
||||
inc Json.83;
|
||||
let Json.84 : U64 = StructAtIndex 1 Json.107;
|
||||
dec Json.107;
|
||||
let Json.135 : I32 = 34i64;
|
||||
let Json.134 : U8 = CallByName Num.123 Json.135;
|
||||
let Json.132 : List U8 = CallByName List.4 Json.83 Json.134;
|
||||
let Json.133 : List U8 = CallByName Str.12 Json.85;
|
||||
let Json.129 : List U8 = CallByName List.8 Json.132 Json.133;
|
||||
let Json.131 : I32 = 34i64;
|
||||
let Json.130 : U8 = CallByName Num.123 Json.131;
|
||||
let Json.126 : List U8 = CallByName List.4 Json.129 Json.130;
|
||||
let Json.128 : I32 = 58i64;
|
||||
let Json.127 : U8 = CallByName Num.123 Json.128;
|
||||
let Json.124 : List U8 = CallByName List.4 Json.126 Json.127;
|
||||
let Json.125 : {} = Struct {};
|
||||
let Json.87 : List U8 = CallByName Encode.23 Json.124 Json.86 Json.125;
|
||||
joinpoint Json.119 Json.88:
|
||||
let Json.117 : U64 = 1i64;
|
||||
let Json.116 : U64 = CallByName Num.20 Json.84 Json.117;
|
||||
let Json.115 : {List U8, U64} = Struct {Json.88, Json.116};
|
||||
ret Json.115;
|
||||
in
|
||||
let Json.123 : U64 = 0i64;
|
||||
let Json.120 : Int1 = CallByName Num.24 Json.84 Json.123;
|
||||
if Json.120 then
|
||||
let Json.122 : I32 = 44i64;
|
||||
let Json.121 : U8 = CallByName Num.123 Json.122;
|
||||
let Json.118 : List U8 = CallByName List.4 Json.87 Json.121;
|
||||
jump Json.119 Json.118;
|
||||
else
|
||||
jump Json.119 Json.87;
|
||||
|
||||
procedure Json.79 (Json.107, Json.108):
|
||||
let Json.85 : Str = StructAtIndex 0 Json.108;
|
||||
inc Json.85;
|
||||
let Json.86 : {Str} = StructAtIndex 1 Json.108;
|
||||
inc Json.86;
|
||||
dec Json.108;
|
||||
let Json.83 : List U8 = StructAtIndex 0 Json.107;
|
||||
inc Json.83;
|
||||
let Json.84 : U64 = StructAtIndex 1 Json.107;
|
||||
dec Json.107;
|
||||
let Json.175 : I32 = 34i64;
|
||||
let Json.174 : U8 = CallByName Num.123 Json.175;
|
||||
let Json.172 : List U8 = CallByName List.4 Json.83 Json.174;
|
||||
let Json.173 : List U8 = CallByName Str.12 Json.85;
|
||||
let Json.169 : List U8 = CallByName List.8 Json.172 Json.173;
|
||||
let Json.171 : I32 = 34i64;
|
||||
let Json.170 : U8 = CallByName Num.123 Json.171;
|
||||
let Json.166 : List U8 = CallByName List.4 Json.169 Json.170;
|
||||
let Json.168 : I32 = 58i64;
|
||||
let Json.167 : U8 = CallByName Num.123 Json.168;
|
||||
let Json.164 : List U8 = CallByName List.4 Json.166 Json.167;
|
||||
let Json.165 : {} = Struct {};
|
||||
let Json.87 : List U8 = CallByName Encode.23 Json.164 Json.86 Json.165;
|
||||
joinpoint Json.159 Json.88:
|
||||
let Json.157 : U64 = 1i64;
|
||||
let Json.156 : U64 = CallByName Num.20 Json.84 Json.157;
|
||||
let Json.155 : {List U8, U64} = Struct {Json.88, Json.156};
|
||||
ret Json.155;
|
||||
in
|
||||
let Json.163 : U64 = 0i64;
|
||||
let Json.160 : Int1 = CallByName Num.24 Json.84 Json.163;
|
||||
if Json.160 then
|
||||
let Json.162 : I32 = 44i64;
|
||||
let Json.161 : U8 = CallByName Num.123 Json.162;
|
||||
let Json.158 : List U8 = CallByName List.4 Json.87 Json.161;
|
||||
jump Json.159 Json.158;
|
||||
else
|
||||
jump Json.159 Json.87;
|
||||
|
||||
procedure List.121 (List.122, List.123, #Attr.12):
|
||||
let List.120 : {} = StructAtIndex 0 #Attr.12;
|
||||
let List.344 : {List U8, U64} = CallByName Json.79 List.122 List.123;
|
||||
let List.343 : [C [], C {List U8, U64}] = TagId(1) List.344;
|
||||
ret List.343;
|
||||
|
||||
procedure List.121 (List.122, List.123, #Attr.12):
|
||||
let List.120 : {} = StructAtIndex 0 #Attr.12;
|
||||
let List.418 : {List U8, U64} = CallByName Json.79 List.122 List.123;
|
||||
let List.417 : [C [], C {List U8, U64}] = TagId(1) List.418;
|
||||
ret List.417;
|
||||
|
||||
procedure List.18 (List.118, List.119, List.120):
|
||||
let List.321 : {{}} = Struct {List.120};
|
||||
let List.315 : [C [], C {List U8, U64}] = CallByName List.63 List.118 List.119 List.321;
|
||||
let List.318 : U8 = 1i64;
|
||||
let List.319 : U8 = GetTagId List.315;
|
||||
let List.320 : Int1 = lowlevel Eq List.318 List.319;
|
||||
if List.320 then
|
||||
let List.125 : {List U8, U64} = UnionAtIndex (Id 1) (Index 0) List.315;
|
||||
inc List.125;
|
||||
dec List.315;
|
||||
ret List.125;
|
||||
else
|
||||
let List.126 : [] = UnionAtIndex (Id 0) (Index 0) List.315;
|
||||
dec List.315;
|
||||
let List.317 : {List U8, U64} = CallByName List.64 List.126;
|
||||
ret List.317;
|
||||
|
||||
procedure List.18 (List.118, List.119, List.120):
|
||||
let List.395 : {{}} = Struct {List.120};
|
||||
let List.389 : [C [], C {List U8, U64}] = CallByName List.63 List.118 List.119 List.395;
|
||||
let List.392 : U8 = 1i64;
|
||||
let List.393 : U8 = GetTagId List.389;
|
||||
let List.394 : Int1 = lowlevel Eq List.392 List.393;
|
||||
if List.394 then
|
||||
let List.125 : {List U8, U64} = UnionAtIndex (Id 1) (Index 0) List.389;
|
||||
inc List.125;
|
||||
dec List.389;
|
||||
ret List.125;
|
||||
else
|
||||
let List.126 : [] = UnionAtIndex (Id 0) (Index 0) List.389;
|
||||
dec List.389;
|
||||
let List.391 : {List U8, U64} = CallByName List.64 List.126;
|
||||
ret List.391;
|
||||
|
||||
procedure List.4 (List.89, List.90):
|
||||
let List.450 : U64 = 1i64;
|
||||
let List.449 : List U8 = CallByName List.65 List.89 List.450;
|
||||
let List.448 : List U8 = CallByName List.66 List.449 List.90;
|
||||
ret List.448;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.295 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.295;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.323 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.323;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.397 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.397;
|
||||
|
||||
procedure List.60 (#Attr.2, #Attr.3):
|
||||
let List.342 : {Str, {Str}} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.342;
|
||||
|
||||
procedure List.60 (#Attr.2, #Attr.3):
|
||||
let List.416 : {Str, {Str}} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.416;
|
||||
|
||||
procedure List.63 (List.283, List.284, List.285):
|
||||
let List.328 : U64 = 0i64;
|
||||
let List.329 : U64 = CallByName List.6 List.283;
|
||||
let List.327 : [C [], C {List U8, U64}] = CallByName List.76 List.283 List.284 List.285 List.328 List.329;
|
||||
ret List.327;
|
||||
|
||||
procedure List.63 (List.283, List.284, List.285):
|
||||
let List.402 : U64 = 0i64;
|
||||
let List.403 : U64 = CallByName List.6 List.283;
|
||||
let List.401 : [C [], C {List U8, U64}] = CallByName List.76 List.283 List.284 List.285 List.402 List.403;
|
||||
ret List.401;
|
||||
|
||||
procedure List.64 (#Attr.2):
|
||||
let List.400 : {List U8, U64} = lowlevel Unreachable #Attr.2;
|
||||
ret List.400;
|
||||
|
||||
procedure List.65 (#Attr.2, #Attr.3):
|
||||
let List.453 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.453;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.452 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.452;
|
||||
|
||||
procedure List.76 (List.361, List.362, List.363, List.364, List.365):
|
||||
joinpoint List.330 List.286 List.287 List.288 List.289 List.290:
|
||||
let List.332 : Int1 = CallByName Num.22 List.289 List.290;
|
||||
if List.332 then
|
||||
let List.341 : {Str, {Str}} = CallByName List.60 List.286 List.289;
|
||||
let List.333 : [C [], C {List U8, U64}] = CallByName List.121 List.287 List.341 List.288;
|
||||
let List.338 : U8 = 1i64;
|
||||
let List.339 : U8 = GetTagId List.333;
|
||||
let List.340 : Int1 = lowlevel Eq List.338 List.339;
|
||||
if List.340 then
|
||||
let List.291 : {List U8, U64} = UnionAtIndex (Id 1) (Index 0) List.333;
|
||||
inc List.291;
|
||||
dec List.333;
|
||||
let List.336 : U64 = 1i64;
|
||||
let List.335 : U64 = CallByName Num.19 List.289 List.336;
|
||||
jump List.330 List.286 List.291 List.288 List.335 List.290;
|
||||
else
|
||||
let List.292 : [] = UnionAtIndex (Id 0) (Index 0) List.333;
|
||||
dec List.333;
|
||||
let List.337 : [C [], C {List U8, U64}] = TagId(0) List.292;
|
||||
ret List.337;
|
||||
else
|
||||
let List.331 : [C [], C {List U8, U64}] = TagId(1) List.287;
|
||||
ret List.331;
|
||||
in
|
||||
jump List.330 List.361 List.362 List.363 List.364 List.365;
|
||||
|
||||
procedure List.76 (List.435, List.436, List.437, List.438, List.439):
|
||||
joinpoint List.404 List.286 List.287 List.288 List.289 List.290:
|
||||
let List.406 : Int1 = CallByName Num.22 List.289 List.290;
|
||||
if List.406 then
|
||||
let List.415 : {Str, {Str}} = CallByName List.60 List.286 List.289;
|
||||
let List.407 : [C [], C {List U8, U64}] = CallByName List.121 List.287 List.415 List.288;
|
||||
let List.412 : U8 = 1i64;
|
||||
let List.413 : U8 = GetTagId List.407;
|
||||
let List.414 : Int1 = lowlevel Eq List.412 List.413;
|
||||
if List.414 then
|
||||
let List.291 : {List U8, U64} = UnionAtIndex (Id 1) (Index 0) List.407;
|
||||
inc List.291;
|
||||
dec List.407;
|
||||
let List.410 : U64 = 1i64;
|
||||
let List.409 : U64 = CallByName Num.19 List.289 List.410;
|
||||
jump List.404 List.286 List.291 List.288 List.409 List.290;
|
||||
else
|
||||
let List.292 : [] = UnionAtIndex (Id 0) (Index 0) List.407;
|
||||
dec List.407;
|
||||
let List.411 : [C [], C {List U8, U64}] = TagId(0) List.292;
|
||||
ret List.411;
|
||||
else
|
||||
let List.405 : [C [], C {List U8, U64}] = TagId(1) List.287;
|
||||
ret List.405;
|
||||
in
|
||||
jump List.404 List.435 List.436 List.437 List.438 List.439;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.451 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.451;
|
||||
|
||||
procedure Num.123 (#Attr.2):
|
||||
let Num.296 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.296;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.284 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.284;
|
||||
|
||||
procedure Num.20 (#Attr.2, #Attr.3):
|
||||
let Num.282 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.282;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.285 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.285;
|
||||
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Num.283 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||
ret Num.283;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.212 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.212;
|
||||
|
||||
procedure Str.48 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let Str.203 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.203;
|
||||
|
||||
procedure Str.9 (Str.68):
|
||||
let Str.201 : U64 = 0i64;
|
||||
let Str.202 : U64 = CallByName List.6 Str.68;
|
||||
let Str.69 : {U64, Str, Int1, U8} = CallByName Str.48 Str.68 Str.201 Str.202;
|
||||
let Str.198 : Int1 = StructAtIndex 2 Str.69;
|
||||
if Str.198 then
|
||||
let Str.200 : Str = StructAtIndex 1 Str.69;
|
||||
inc Str.200;
|
||||
dec Str.69;
|
||||
let Str.199 : [C {U64, U8}, C Str] = TagId(1) Str.200;
|
||||
ret Str.199;
|
||||
else
|
||||
let Str.196 : U8 = StructAtIndex 3 Str.69;
|
||||
let Str.197 : U64 = StructAtIndex 0 Str.69;
|
||||
dec Str.69;
|
||||
let Str.195 : {U64, U8} = Struct {Str.197, Str.196};
|
||||
let Str.194 : [C {U64, U8}, C Str] = TagId(0) Str.195;
|
||||
ret Str.194;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.12 : Str = "bar";
|
||||
let Test.10 : {} = CallByName Json.1;
|
||||
let Test.8 : List U8 = CallByName Encode.25 Test.12 Test.10;
|
||||
let Test.1 : [C {U64, U8}, C Str] = CallByName Str.9 Test.8;
|
||||
dec Test.8;
|
||||
let Test.5 : U8 = 1i64;
|
||||
let Test.6 : U8 = GetTagId Test.1;
|
||||
let Test.7 : Int1 = lowlevel Eq Test.5 Test.6;
|
||||
if Test.7 then
|
||||
let Test.2 : Str = UnionAtIndex (Id 1) (Index 0) Test.1;
|
||||
inc Test.2;
|
||||
dec Test.1;
|
||||
ret Test.2;
|
||||
else
|
||||
dec Test.1;
|
||||
let Test.4 : Str = "<bad>";
|
||||
ret Test.4;
|
|
@ -0,0 +1,306 @@
|
|||
procedure #Derived.0 (#Derived.1):
|
||||
let #Derived_gen.1 : {Str} = Struct {#Derived.1};
|
||||
let #Derived_gen.0 : {Str} = CallByName Encode.22 #Derived_gen.1;
|
||||
ret #Derived_gen.0;
|
||||
|
||||
procedure #Derived.2 (#Derived.3, #Derived.4, #Attr.12):
|
||||
let #Derived.1 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc #Derived.1;
|
||||
dec #Attr.12;
|
||||
let #Derived_gen.7 : Str = "a";
|
||||
let #Derived_gen.8 : {Str} = CallByName #Derived.5 #Derived.1;
|
||||
let #Derived_gen.6 : {Str, {Str}} = Struct {#Derived_gen.7, #Derived_gen.8};
|
||||
let #Derived_gen.5 : List {Str, {Str}} = Array [#Derived_gen.6];
|
||||
let #Derived_gen.4 : {List {Str, {Str}}} = CallByName Json.19 #Derived_gen.5;
|
||||
let #Derived_gen.3 : List U8 = CallByName Encode.23 #Derived.3 #Derived_gen.4 #Derived.4;
|
||||
ret #Derived_gen.3;
|
||||
|
||||
procedure #Derived.5 (#Derived.6):
|
||||
let #Derived_gen.15 : {Str} = Struct {#Derived.6};
|
||||
let #Derived_gen.14 : {Str} = CallByName Encode.22 #Derived_gen.15;
|
||||
ret #Derived_gen.14;
|
||||
|
||||
procedure #Derived.7 (#Derived.8, #Derived.9, #Attr.12):
|
||||
let #Derived.6 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc #Derived.6;
|
||||
dec #Attr.12;
|
||||
let #Derived_gen.18 : {Str} = CallByName Json.17 #Derived.6;
|
||||
let #Derived_gen.17 : List U8 = CallByName Encode.23 #Derived.8 #Derived_gen.18 #Derived.9;
|
||||
ret #Derived_gen.17;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.106 : List U8 = CallByName #Derived.2 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.106;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.113 : List U8 = CallByName Json.77 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.113;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.115 : List U8 = CallByName #Derived.7 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.115;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.125 : List U8 = CallByName Json.65 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.125;
|
||||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
let Encode.104 : List U8 = Array [];
|
||||
let Encode.105 : {Str} = CallByName #Derived.0 Encode.100;
|
||||
let Encode.103 : List U8 = CallByName Encode.23 Encode.104 Encode.105 Encode.101;
|
||||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.102 : {} = Struct {};
|
||||
ret Json.102;
|
||||
|
||||
procedure Json.17 (Json.64):
|
||||
let Json.146 : {Str} = Struct {Json.64};
|
||||
let Json.145 : {Str} = CallByName Encode.22 Json.146;
|
||||
ret Json.145;
|
||||
|
||||
procedure Json.19 (Json.76):
|
||||
let Json.104 : {List {Str, {Str}}} = Struct {Json.76};
|
||||
let Json.103 : {List {Str, {Str}}} = CallByName Encode.22 Json.104;
|
||||
ret Json.103;
|
||||
|
||||
procedure Json.65 (Json.66, Json.147, #Attr.12):
|
||||
let Json.64 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.64;
|
||||
dec #Attr.12;
|
||||
let Json.156 : I32 = 34i64;
|
||||
let Json.155 : U8 = CallByName Num.123 Json.156;
|
||||
let Json.153 : List U8 = CallByName List.4 Json.66 Json.155;
|
||||
let Json.154 : List U8 = CallByName Str.12 Json.64;
|
||||
let Json.150 : List U8 = CallByName List.8 Json.153 Json.154;
|
||||
let Json.152 : I32 = 34i64;
|
||||
let Json.151 : U8 = CallByName Num.123 Json.152;
|
||||
let Json.149 : List U8 = CallByName List.4 Json.150 Json.151;
|
||||
ret Json.149;
|
||||
|
||||
procedure Json.77 (Json.78, Json.105, #Attr.12):
|
||||
let Json.76 : List {Str, {Str}} = StructAtIndex 0 #Attr.12;
|
||||
inc Json.76;
|
||||
dec #Attr.12;
|
||||
let Json.138 : I32 = 123i64;
|
||||
let Json.137 : U8 = CallByName Num.123 Json.138;
|
||||
let Json.80 : List U8 = CallByName List.4 Json.78 Json.137;
|
||||
let Json.136 : U64 = CallByName List.6 Json.76;
|
||||
let Json.113 : {List U8, U64} = Struct {Json.80, Json.136};
|
||||
let Json.114 : {} = Struct {};
|
||||
let Json.112 : {List U8, U64} = CallByName List.18 Json.76 Json.113 Json.114;
|
||||
dec Json.76;
|
||||
let Json.82 : List U8 = StructAtIndex 0 Json.112;
|
||||
inc Json.82;
|
||||
dec Json.112;
|
||||
let Json.111 : I32 = 125i64;
|
||||
let Json.110 : U8 = CallByName Num.123 Json.111;
|
||||
let Json.109 : List U8 = CallByName List.4 Json.82 Json.110;
|
||||
ret Json.109;
|
||||
|
||||
procedure Json.79 (Json.107, Json.108):
|
||||
let Json.85 : Str = StructAtIndex 0 Json.108;
|
||||
inc Json.85;
|
||||
let Json.86 : {Str} = StructAtIndex 1 Json.108;
|
||||
inc Json.86;
|
||||
dec Json.108;
|
||||
let Json.83 : List U8 = StructAtIndex 0 Json.107;
|
||||
inc Json.83;
|
||||
let Json.84 : U64 = StructAtIndex 1 Json.107;
|
||||
dec Json.107;
|
||||
let Json.135 : I32 = 34i64;
|
||||
let Json.134 : U8 = CallByName Num.123 Json.135;
|
||||
let Json.132 : List U8 = CallByName List.4 Json.83 Json.134;
|
||||
let Json.133 : List U8 = CallByName Str.12 Json.85;
|
||||
let Json.129 : List U8 = CallByName List.8 Json.132 Json.133;
|
||||
let Json.131 : I32 = 34i64;
|
||||
let Json.130 : U8 = CallByName Num.123 Json.131;
|
||||
let Json.126 : List U8 = CallByName List.4 Json.129 Json.130;
|
||||
let Json.128 : I32 = 58i64;
|
||||
let Json.127 : U8 = CallByName Num.123 Json.128;
|
||||
let Json.124 : List U8 = CallByName List.4 Json.126 Json.127;
|
||||
let Json.125 : {} = Struct {};
|
||||
let Json.87 : List U8 = CallByName Encode.23 Json.124 Json.86 Json.125;
|
||||
joinpoint Json.119 Json.88:
|
||||
let Json.117 : U64 = 1i64;
|
||||
let Json.116 : U64 = CallByName Num.20 Json.84 Json.117;
|
||||
let Json.115 : {List U8, U64} = Struct {Json.88, Json.116};
|
||||
ret Json.115;
|
||||
in
|
||||
let Json.123 : U64 = 0i64;
|
||||
let Json.120 : Int1 = CallByName Num.24 Json.84 Json.123;
|
||||
if Json.120 then
|
||||
let Json.122 : I32 = 44i64;
|
||||
let Json.121 : U8 = CallByName Num.123 Json.122;
|
||||
let Json.118 : List U8 = CallByName List.4 Json.87 Json.121;
|
||||
jump Json.119 Json.118;
|
||||
else
|
||||
jump Json.119 Json.87;
|
||||
|
||||
procedure List.121 (List.122, List.123, #Attr.12):
|
||||
let List.120 : {} = StructAtIndex 0 #Attr.12;
|
||||
let List.344 : {List U8, U64} = CallByName Json.79 List.122 List.123;
|
||||
let List.343 : [C [], C {List U8, U64}] = TagId(1) List.344;
|
||||
ret List.343;
|
||||
|
||||
procedure List.18 (List.118, List.119, List.120):
|
||||
let List.321 : {{}} = Struct {List.120};
|
||||
let List.315 : [C [], C {List U8, U64}] = CallByName List.63 List.118 List.119 List.321;
|
||||
let List.318 : U8 = 1i64;
|
||||
let List.319 : U8 = GetTagId List.315;
|
||||
let List.320 : Int1 = lowlevel Eq List.318 List.319;
|
||||
if List.320 then
|
||||
let List.125 : {List U8, U64} = UnionAtIndex (Id 1) (Index 0) List.315;
|
||||
inc List.125;
|
||||
dec List.315;
|
||||
ret List.125;
|
||||
else
|
||||
let List.126 : [] = UnionAtIndex (Id 0) (Index 0) List.315;
|
||||
dec List.315;
|
||||
let List.317 : {List U8, U64} = CallByName List.64 List.126;
|
||||
ret List.317;
|
||||
|
||||
procedure List.4 (List.89, List.90):
|
||||
let List.376 : U64 = 1i64;
|
||||
let List.375 : List U8 = CallByName List.65 List.89 List.376;
|
||||
let List.374 : List U8 = CallByName List.66 List.375 List.90;
|
||||
ret List.374;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.295 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.295;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.323 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.323;
|
||||
|
||||
procedure List.60 (#Attr.2, #Attr.3):
|
||||
let List.342 : {Str, {Str}} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.342;
|
||||
|
||||
procedure List.63 (List.283, List.284, List.285):
|
||||
let List.328 : U64 = 0i64;
|
||||
let List.329 : U64 = CallByName List.6 List.283;
|
||||
let List.327 : [C [], C {List U8, U64}] = CallByName List.76 List.283 List.284 List.285 List.328 List.329;
|
||||
ret List.327;
|
||||
|
||||
procedure List.64 (#Attr.2):
|
||||
let List.326 : {List U8, U64} = lowlevel Unreachable #Attr.2;
|
||||
ret List.326;
|
||||
|
||||
procedure List.65 (#Attr.2, #Attr.3):
|
||||
let List.379 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.379;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.378 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.378;
|
||||
|
||||
procedure List.76 (List.361, List.362, List.363, List.364, List.365):
|
||||
joinpoint List.330 List.286 List.287 List.288 List.289 List.290:
|
||||
let List.332 : Int1 = CallByName Num.22 List.289 List.290;
|
||||
if List.332 then
|
||||
let List.341 : {Str, {Str}} = CallByName List.60 List.286 List.289;
|
||||
let List.333 : [C [], C {List U8, U64}] = CallByName List.121 List.287 List.341 List.288;
|
||||
let List.338 : U8 = 1i64;
|
||||
let List.339 : U8 = GetTagId List.333;
|
||||
let List.340 : Int1 = lowlevel Eq List.338 List.339;
|
||||
if List.340 then
|
||||
let List.291 : {List U8, U64} = UnionAtIndex (Id 1) (Index 0) List.333;
|
||||
inc List.291;
|
||||
dec List.333;
|
||||
let List.336 : U64 = 1i64;
|
||||
let List.335 : U64 = CallByName Num.19 List.289 List.336;
|
||||
jump List.330 List.286 List.291 List.288 List.335 List.290;
|
||||
else
|
||||
let List.292 : [] = UnionAtIndex (Id 0) (Index 0) List.333;
|
||||
dec List.333;
|
||||
let List.337 : [C [], C {List U8, U64}] = TagId(0) List.292;
|
||||
ret List.337;
|
||||
else
|
||||
let List.331 : [C [], C {List U8, U64}] = TagId(1) List.287;
|
||||
ret List.331;
|
||||
in
|
||||
jump List.330 List.361 List.362 List.363 List.364 List.365;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.377 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.377;
|
||||
|
||||
procedure Num.123 (#Attr.2):
|
||||
let Num.277 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.277;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.265 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.265;
|
||||
|
||||
procedure Num.20 (#Attr.2, #Attr.3):
|
||||
let Num.263 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.263;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.266 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.266;
|
||||
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Num.264 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||
ret Num.264;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.210 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.210;
|
||||
|
||||
procedure Str.48 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let Str.203 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.203;
|
||||
|
||||
procedure Str.9 (Str.68):
|
||||
let Str.201 : U64 = 0i64;
|
||||
let Str.202 : U64 = CallByName List.6 Str.68;
|
||||
let Str.69 : {U64, Str, Int1, U8} = CallByName Str.48 Str.68 Str.201 Str.202;
|
||||
let Str.198 : Int1 = StructAtIndex 2 Str.69;
|
||||
if Str.198 then
|
||||
let Str.200 : Str = StructAtIndex 1 Str.69;
|
||||
inc Str.200;
|
||||
dec Str.69;
|
||||
let Str.199 : [C {U64, U8}, C Str] = TagId(1) Str.200;
|
||||
ret Str.199;
|
||||
else
|
||||
let Str.196 : U8 = StructAtIndex 3 Str.69;
|
||||
let Str.197 : U64 = StructAtIndex 0 Str.69;
|
||||
dec Str.69;
|
||||
let Str.195 : {U64, U8} = Struct {Str.197, Str.196};
|
||||
let Str.194 : [C {U64, U8}, C Str] = TagId(0) Str.195;
|
||||
ret Str.194;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.11 : Str = "foo";
|
||||
let Test.10 : {} = CallByName Json.1;
|
||||
let Test.8 : List U8 = CallByName Encode.25 Test.11 Test.10;
|
||||
let Test.1 : [C {U64, U8}, C Str] = CallByName Str.9 Test.8;
|
||||
dec Test.8;
|
||||
let Test.5 : U8 = 1i64;
|
||||
let Test.6 : U8 = GetTagId Test.1;
|
||||
let Test.7 : Int1 = lowlevel Eq Test.5 Test.6;
|
||||
if Test.7 then
|
||||
let Test.2 : Str = UnionAtIndex (Id 1) (Index 0) Test.1;
|
||||
inc Test.2;
|
||||
dec Test.1;
|
||||
ret Test.2;
|
||||
else
|
||||
dec Test.1;
|
||||
let Test.4 : Str = "<bad>";
|
||||
ret Test.4;
|
|
@ -0,0 +1,316 @@
|
|||
procedure #Derived.0 (#Derived.1):
|
||||
let #Derived_gen.1 : {{Str, Str}} = Struct {#Derived.1};
|
||||
let #Derived_gen.0 : {{Str, Str}} = CallByName Encode.22 #Derived_gen.1;
|
||||
ret #Derived_gen.0;
|
||||
|
||||
procedure #Derived.2 (#Derived.3, #Derived.4, #Attr.12):
|
||||
let #Derived.1 : {Str, Str} = StructAtIndex 0 #Attr.12;
|
||||
inc #Derived.1;
|
||||
dec #Attr.12;
|
||||
let #Derived_gen.11 : Str = "a";
|
||||
let #Derived_gen.13 : Str = StructAtIndex 0 #Derived.1;
|
||||
inc #Derived_gen.13;
|
||||
let #Derived_gen.12 : {Str} = CallByName #Derived.5 #Derived_gen.13;
|
||||
let #Derived_gen.6 : {Str, {Str}} = Struct {#Derived_gen.11, #Derived_gen.12};
|
||||
let #Derived_gen.8 : Str = "b";
|
||||
let #Derived_gen.10 : Str = StructAtIndex 1 #Derived.1;
|
||||
inc #Derived_gen.10;
|
||||
dec #Derived.1;
|
||||
let #Derived_gen.9 : {Str} = CallByName #Derived.5 #Derived_gen.10;
|
||||
let #Derived_gen.7 : {Str, {Str}} = Struct {#Derived_gen.8, #Derived_gen.9};
|
||||
let #Derived_gen.5 : List {Str, {Str}} = Array [#Derived_gen.6, #Derived_gen.7];
|
||||
let #Derived_gen.4 : {List {Str, {Str}}} = CallByName Json.19 #Derived_gen.5;
|
||||
let #Derived_gen.3 : List U8 = CallByName Encode.23 #Derived.3 #Derived_gen.4 #Derived.4;
|
||||
ret #Derived_gen.3;
|
||||
|
||||
procedure #Derived.5 (#Derived.6):
|
||||
let #Derived_gen.21 : {Str} = Struct {#Derived.6};
|
||||
let #Derived_gen.20 : {Str} = CallByName Encode.22 #Derived_gen.21;
|
||||
ret #Derived_gen.20;
|
||||
|
||||
procedure #Derived.7 (#Derived.8, #Derived.9, #Attr.12):
|
||||
let #Derived.6 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc #Derived.6;
|
||||
dec #Attr.12;
|
||||
let #Derived_gen.24 : {Str} = CallByName Json.17 #Derived.6;
|
||||
let #Derived_gen.23 : List U8 = CallByName Encode.23 #Derived.8 #Derived_gen.24 #Derived.9;
|
||||
ret #Derived_gen.23;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.106 : List U8 = CallByName #Derived.2 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.106;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.113 : List U8 = CallByName Json.77 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.113;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.115 : List U8 = CallByName #Derived.7 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.115;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.126 : List U8 = CallByName Json.65 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.126;
|
||||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
let Encode.104 : List U8 = Array [];
|
||||
let Encode.105 : {{Str, Str}} = CallByName #Derived.0 Encode.100;
|
||||
let Encode.103 : List U8 = CallByName Encode.23 Encode.104 Encode.105 Encode.101;
|
||||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.102 : {} = Struct {};
|
||||
ret Json.102;
|
||||
|
||||
procedure Json.17 (Json.64):
|
||||
let Json.146 : {Str} = Struct {Json.64};
|
||||
let Json.145 : {Str} = CallByName Encode.22 Json.146;
|
||||
ret Json.145;
|
||||
|
||||
procedure Json.19 (Json.76):
|
||||
let Json.104 : {List {Str, {Str}}} = Struct {Json.76};
|
||||
let Json.103 : {List {Str, {Str}}} = CallByName Encode.22 Json.104;
|
||||
ret Json.103;
|
||||
|
||||
procedure Json.65 (Json.66, Json.147, #Attr.12):
|
||||
let Json.64 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.64;
|
||||
dec #Attr.12;
|
||||
let Json.156 : I32 = 34i64;
|
||||
let Json.155 : U8 = CallByName Num.123 Json.156;
|
||||
let Json.153 : List U8 = CallByName List.4 Json.66 Json.155;
|
||||
let Json.154 : List U8 = CallByName Str.12 Json.64;
|
||||
let Json.150 : List U8 = CallByName List.8 Json.153 Json.154;
|
||||
let Json.152 : I32 = 34i64;
|
||||
let Json.151 : U8 = CallByName Num.123 Json.152;
|
||||
let Json.149 : List U8 = CallByName List.4 Json.150 Json.151;
|
||||
ret Json.149;
|
||||
|
||||
procedure Json.77 (Json.78, Json.105, #Attr.12):
|
||||
let Json.76 : List {Str, {Str}} = StructAtIndex 0 #Attr.12;
|
||||
inc Json.76;
|
||||
dec #Attr.12;
|
||||
let Json.138 : I32 = 123i64;
|
||||
let Json.137 : U8 = CallByName Num.123 Json.138;
|
||||
let Json.80 : List U8 = CallByName List.4 Json.78 Json.137;
|
||||
let Json.136 : U64 = CallByName List.6 Json.76;
|
||||
let Json.113 : {List U8, U64} = Struct {Json.80, Json.136};
|
||||
let Json.114 : {} = Struct {};
|
||||
let Json.112 : {List U8, U64} = CallByName List.18 Json.76 Json.113 Json.114;
|
||||
dec Json.76;
|
||||
let Json.82 : List U8 = StructAtIndex 0 Json.112;
|
||||
inc Json.82;
|
||||
dec Json.112;
|
||||
let Json.111 : I32 = 125i64;
|
||||
let Json.110 : U8 = CallByName Num.123 Json.111;
|
||||
let Json.109 : List U8 = CallByName List.4 Json.82 Json.110;
|
||||
ret Json.109;
|
||||
|
||||
procedure Json.79 (Json.107, Json.108):
|
||||
let Json.85 : Str = StructAtIndex 0 Json.108;
|
||||
inc Json.85;
|
||||
let Json.86 : {Str} = StructAtIndex 1 Json.108;
|
||||
inc Json.86;
|
||||
dec Json.108;
|
||||
let Json.83 : List U8 = StructAtIndex 0 Json.107;
|
||||
inc Json.83;
|
||||
let Json.84 : U64 = StructAtIndex 1 Json.107;
|
||||
dec Json.107;
|
||||
let Json.135 : I32 = 34i64;
|
||||
let Json.134 : U8 = CallByName Num.123 Json.135;
|
||||
let Json.132 : List U8 = CallByName List.4 Json.83 Json.134;
|
||||
let Json.133 : List U8 = CallByName Str.12 Json.85;
|
||||
let Json.129 : List U8 = CallByName List.8 Json.132 Json.133;
|
||||
let Json.131 : I32 = 34i64;
|
||||
let Json.130 : U8 = CallByName Num.123 Json.131;
|
||||
let Json.126 : List U8 = CallByName List.4 Json.129 Json.130;
|
||||
let Json.128 : I32 = 58i64;
|
||||
let Json.127 : U8 = CallByName Num.123 Json.128;
|
||||
let Json.124 : List U8 = CallByName List.4 Json.126 Json.127;
|
||||
let Json.125 : {} = Struct {};
|
||||
let Json.87 : List U8 = CallByName Encode.23 Json.124 Json.86 Json.125;
|
||||
joinpoint Json.119 Json.88:
|
||||
let Json.117 : U64 = 1i64;
|
||||
let Json.116 : U64 = CallByName Num.20 Json.84 Json.117;
|
||||
let Json.115 : {List U8, U64} = Struct {Json.88, Json.116};
|
||||
ret Json.115;
|
||||
in
|
||||
let Json.123 : U64 = 0i64;
|
||||
let Json.120 : Int1 = CallByName Num.24 Json.84 Json.123;
|
||||
if Json.120 then
|
||||
let Json.122 : I32 = 44i64;
|
||||
let Json.121 : U8 = CallByName Num.123 Json.122;
|
||||
let Json.118 : List U8 = CallByName List.4 Json.87 Json.121;
|
||||
jump Json.119 Json.118;
|
||||
else
|
||||
jump Json.119 Json.87;
|
||||
|
||||
procedure List.121 (List.122, List.123, #Attr.12):
|
||||
let List.120 : {} = StructAtIndex 0 #Attr.12;
|
||||
let List.344 : {List U8, U64} = CallByName Json.79 List.122 List.123;
|
||||
let List.343 : [C [], C {List U8, U64}] = TagId(1) List.344;
|
||||
ret List.343;
|
||||
|
||||
procedure List.18 (List.118, List.119, List.120):
|
||||
let List.321 : {{}} = Struct {List.120};
|
||||
let List.315 : [C [], C {List U8, U64}] = CallByName List.63 List.118 List.119 List.321;
|
||||
let List.318 : U8 = 1i64;
|
||||
let List.319 : U8 = GetTagId List.315;
|
||||
let List.320 : Int1 = lowlevel Eq List.318 List.319;
|
||||
if List.320 then
|
||||
let List.125 : {List U8, U64} = UnionAtIndex (Id 1) (Index 0) List.315;
|
||||
inc List.125;
|
||||
dec List.315;
|
||||
ret List.125;
|
||||
else
|
||||
let List.126 : [] = UnionAtIndex (Id 0) (Index 0) List.315;
|
||||
dec List.315;
|
||||
let List.317 : {List U8, U64} = CallByName List.64 List.126;
|
||||
ret List.317;
|
||||
|
||||
procedure List.4 (List.89, List.90):
|
||||
let List.376 : U64 = 1i64;
|
||||
let List.375 : List U8 = CallByName List.65 List.89 List.376;
|
||||
let List.374 : List U8 = CallByName List.66 List.375 List.90;
|
||||
ret List.374;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.295 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.295;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.323 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.323;
|
||||
|
||||
procedure List.60 (#Attr.2, #Attr.3):
|
||||
let List.342 : {Str, {Str}} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.342;
|
||||
|
||||
procedure List.63 (List.283, List.284, List.285):
|
||||
let List.328 : U64 = 0i64;
|
||||
let List.329 : U64 = CallByName List.6 List.283;
|
||||
let List.327 : [C [], C {List U8, U64}] = CallByName List.76 List.283 List.284 List.285 List.328 List.329;
|
||||
ret List.327;
|
||||
|
||||
procedure List.64 (#Attr.2):
|
||||
let List.326 : {List U8, U64} = lowlevel Unreachable #Attr.2;
|
||||
ret List.326;
|
||||
|
||||
procedure List.65 (#Attr.2, #Attr.3):
|
||||
let List.379 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.379;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.378 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.378;
|
||||
|
||||
procedure List.76 (List.361, List.362, List.363, List.364, List.365):
|
||||
joinpoint List.330 List.286 List.287 List.288 List.289 List.290:
|
||||
let List.332 : Int1 = CallByName Num.22 List.289 List.290;
|
||||
if List.332 then
|
||||
let List.341 : {Str, {Str}} = CallByName List.60 List.286 List.289;
|
||||
let List.333 : [C [], C {List U8, U64}] = CallByName List.121 List.287 List.341 List.288;
|
||||
let List.338 : U8 = 1i64;
|
||||
let List.339 : U8 = GetTagId List.333;
|
||||
let List.340 : Int1 = lowlevel Eq List.338 List.339;
|
||||
if List.340 then
|
||||
let List.291 : {List U8, U64} = UnionAtIndex (Id 1) (Index 0) List.333;
|
||||
inc List.291;
|
||||
dec List.333;
|
||||
let List.336 : U64 = 1i64;
|
||||
let List.335 : U64 = CallByName Num.19 List.289 List.336;
|
||||
jump List.330 List.286 List.291 List.288 List.335 List.290;
|
||||
else
|
||||
let List.292 : [] = UnionAtIndex (Id 0) (Index 0) List.333;
|
||||
dec List.333;
|
||||
let List.337 : [C [], C {List U8, U64}] = TagId(0) List.292;
|
||||
ret List.337;
|
||||
else
|
||||
let List.331 : [C [], C {List U8, U64}] = TagId(1) List.287;
|
||||
ret List.331;
|
||||
in
|
||||
jump List.330 List.361 List.362 List.363 List.364 List.365;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.377 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.377;
|
||||
|
||||
procedure Num.123 (#Attr.2):
|
||||
let Num.277 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.277;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.265 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.265;
|
||||
|
||||
procedure Num.20 (#Attr.2, #Attr.3):
|
||||
let Num.263 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.263;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.266 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.266;
|
||||
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Num.264 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||
ret Num.264;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.210 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.210;
|
||||
|
||||
procedure Str.48 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let Str.203 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.203;
|
||||
|
||||
procedure Str.9 (Str.68):
|
||||
let Str.201 : U64 = 0i64;
|
||||
let Str.202 : U64 = CallByName List.6 Str.68;
|
||||
let Str.69 : {U64, Str, Int1, U8} = CallByName Str.48 Str.68 Str.201 Str.202;
|
||||
let Str.198 : Int1 = StructAtIndex 2 Str.69;
|
||||
if Str.198 then
|
||||
let Str.200 : Str = StructAtIndex 1 Str.69;
|
||||
inc Str.200;
|
||||
dec Str.69;
|
||||
let Str.199 : [C {U64, U8}, C Str] = TagId(1) Str.200;
|
||||
ret Str.199;
|
||||
else
|
||||
let Str.196 : U8 = StructAtIndex 3 Str.69;
|
||||
let Str.197 : U64 = StructAtIndex 0 Str.69;
|
||||
dec Str.69;
|
||||
let Str.195 : {U64, U8} = Struct {Str.197, Str.196};
|
||||
let Str.194 : [C {U64, U8}, C Str] = TagId(0) Str.195;
|
||||
ret Str.194;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.11 : Str = "foo";
|
||||
let Test.12 : Str = "bar";
|
||||
let Test.9 : {Str, Str} = Struct {Test.11, Test.12};
|
||||
let Test.10 : {} = CallByName Json.1;
|
||||
let Test.8 : List U8 = CallByName Encode.25 Test.9 Test.10;
|
||||
let Test.1 : [C {U64, U8}, C Str] = CallByName Str.9 Test.8;
|
||||
dec Test.8;
|
||||
let Test.5 : U8 = 1i64;
|
||||
let Test.6 : U8 = GetTagId Test.1;
|
||||
let Test.7 : Int1 = lowlevel Eq Test.5 Test.6;
|
||||
if Test.7 then
|
||||
let Test.2 : Str = UnionAtIndex (Id 1) (Index 0) Test.1;
|
||||
inc Test.2;
|
||||
dec Test.1;
|
||||
ret Test.2;
|
||||
else
|
||||
dec Test.1;
|
||||
let Test.4 : Str = "<bad>";
|
||||
ret Test.4;
|
127
crates/compiler/test_mono/generated/encode_derived_string.txt
Normal file
127
crates/compiler/test_mono/generated/encode_derived_string.txt
Normal file
|
@ -0,0 +1,127 @@
|
|||
procedure #Derived.0 (#Derived.1):
|
||||
let #Derived_gen.1 : {Str} = Struct {#Derived.1};
|
||||
let #Derived_gen.0 : {Str} = CallByName Encode.22 #Derived_gen.1;
|
||||
ret #Derived_gen.0;
|
||||
|
||||
procedure #Derived.2 (#Derived.3, #Derived.4, #Attr.12):
|
||||
let #Derived.1 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc #Derived.1;
|
||||
dec #Attr.12;
|
||||
let #Derived_gen.4 : {Str} = CallByName Json.17 #Derived.1;
|
||||
let #Derived_gen.3 : List U8 = CallByName Encode.23 #Derived.3 #Derived_gen.4 #Derived.4;
|
||||
ret #Derived_gen.3;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.106 : List U8 = CallByName #Derived.2 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.106;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.113 : List U8 = CallByName Json.65 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.113;
|
||||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
let Encode.104 : List U8 = Array [];
|
||||
let Encode.105 : {Str} = CallByName #Derived.0 Encode.100;
|
||||
let Encode.103 : List U8 = CallByName Encode.23 Encode.104 Encode.105 Encode.101;
|
||||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.102 : {} = Struct {};
|
||||
ret Json.102;
|
||||
|
||||
procedure Json.17 (Json.64):
|
||||
let Json.104 : {Str} = Struct {Json.64};
|
||||
let Json.103 : {Str} = CallByName Encode.22 Json.104;
|
||||
ret Json.103;
|
||||
|
||||
procedure Json.65 (Json.66, Json.105, #Attr.12):
|
||||
let Json.64 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.64;
|
||||
dec #Attr.12;
|
||||
let Json.114 : I32 = 34i64;
|
||||
let Json.113 : U8 = CallByName Num.123 Json.114;
|
||||
let Json.111 : List U8 = CallByName List.4 Json.66 Json.113;
|
||||
let Json.112 : List U8 = CallByName Str.12 Json.64;
|
||||
let Json.108 : List U8 = CallByName List.8 Json.111 Json.112;
|
||||
let Json.110 : I32 = 34i64;
|
||||
let Json.109 : U8 = CallByName Num.123 Json.110;
|
||||
let Json.107 : List U8 = CallByName List.4 Json.108 Json.109;
|
||||
ret Json.107;
|
||||
|
||||
procedure List.4 (List.89, List.90):
|
||||
let List.302 : U64 = 1i64;
|
||||
let List.301 : List U8 = CallByName List.65 List.89 List.302;
|
||||
let List.300 : List U8 = CallByName List.66 List.301 List.90;
|
||||
ret List.300;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.295 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.295;
|
||||
|
||||
procedure List.65 (#Attr.2, #Attr.3):
|
||||
let List.305 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.305;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.304 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.304;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.303 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.303;
|
||||
|
||||
procedure Num.123 (#Attr.2):
|
||||
let Num.258 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.258;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.208 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.208;
|
||||
|
||||
procedure Str.48 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let Str.203 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.203;
|
||||
|
||||
procedure Str.9 (Str.68):
|
||||
let Str.201 : U64 = 0i64;
|
||||
let Str.202 : U64 = CallByName List.6 Str.68;
|
||||
let Str.69 : {U64, Str, Int1, U8} = CallByName Str.48 Str.68 Str.201 Str.202;
|
||||
let Str.198 : Int1 = StructAtIndex 2 Str.69;
|
||||
if Str.198 then
|
||||
let Str.200 : Str = StructAtIndex 1 Str.69;
|
||||
inc Str.200;
|
||||
dec Str.69;
|
||||
let Str.199 : [C {U64, U8}, C Str] = TagId(1) Str.200;
|
||||
ret Str.199;
|
||||
else
|
||||
let Str.196 : U8 = StructAtIndex 3 Str.69;
|
||||
let Str.197 : U64 = StructAtIndex 0 Str.69;
|
||||
dec Str.69;
|
||||
let Str.195 : {U64, U8} = Struct {Str.197, Str.196};
|
||||
let Str.194 : [C {U64, U8}, C Str] = TagId(0) Str.195;
|
||||
ret Str.194;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.9 : Str = "abc";
|
||||
let Test.10 : {} = CallByName Json.1;
|
||||
let Test.8 : List U8 = CallByName Encode.25 Test.9 Test.10;
|
||||
let Test.1 : [C {U64, U8}, C Str] = CallByName Str.9 Test.8;
|
||||
dec Test.8;
|
||||
let Test.5 : U8 = 1i64;
|
||||
let Test.6 : U8 = GetTagId Test.1;
|
||||
let Test.7 : Int1 = lowlevel Eq Test.5 Test.6;
|
||||
if Test.7 then
|
||||
let Test.2 : Str = UnionAtIndex (Id 1) (Index 0) Test.1;
|
||||
inc Test.2;
|
||||
dec Test.1;
|
||||
ret Test.2;
|
||||
else
|
||||
dec Test.1;
|
||||
let Test.4 : Str = "<bad>";
|
||||
ret Test.4;
|
|
@ -1,7 +1,7 @@
|
|||
procedure List.28 (#Attr.2, #Attr.3):
|
||||
let List.297 : List I64 = lowlevel ListSortWith { xs: `#Attr.#arg1` } #Attr.2 Num.46 #Attr.3;
|
||||
let Bool.9 : Int1 = lowlevel ListIsUnique #Attr.2;
|
||||
if Bool.9 then
|
||||
let #Derived_gen.0 : Int1 = lowlevel ListIsUnique #Attr.2;
|
||||
if #Derived_gen.0 then
|
||||
ret List.297;
|
||||
else
|
||||
decref #Attr.2;
|
||||
|
|
|
@ -1467,7 +1467,24 @@ fn encode_custom_type() {
|
|||
}
|
||||
|
||||
#[mono_test]
|
||||
#[ignore]
|
||||
fn encode_derived_string() {
|
||||
indoc!(
|
||||
r#"
|
||||
app "test"
|
||||
imports [Encode.{ toEncoder }, Json]
|
||||
provides [main] to "./platform"
|
||||
|
||||
main =
|
||||
result = Str.fromUtf8 (Encode.toBytes "abc" Json.format)
|
||||
when result is
|
||||
Ok s -> s
|
||||
_ -> "<bad>"
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
#[ignore = "TODO"]
|
||||
fn encode_derived_record() {
|
||||
indoc!(
|
||||
r#"
|
||||
|
@ -1476,7 +1493,7 @@ fn encode_derived_record() {
|
|||
provides [main] to "./platform"
|
||||
|
||||
main =
|
||||
result = Str.fromUtf8 (Encode.toBytes {a: "fieldA", b: "fieldB"} Json.format)
|
||||
result = Str.fromUtf8 (Encode.toBytes {a: "a"} Json.format)
|
||||
when result is
|
||||
Ok s -> s
|
||||
_ -> "<bad>"
|
||||
|
@ -1780,3 +1797,74 @@ fn instantiate_annotated_as_recursive_alias_multiple_polymorphic_expr() {
|
|||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn encode_derived_record_one_field_string() {
|
||||
indoc!(
|
||||
r#"
|
||||
app "test"
|
||||
imports [Encode.{ toEncoder }, Json]
|
||||
provides [main] to "./platform"
|
||||
|
||||
main =
|
||||
result = Str.fromUtf8 (Encode.toBytes {a: "foo"} Json.format)
|
||||
when result is
|
||||
Ok s -> s
|
||||
_ -> "<bad>"
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn encode_derived_record_two_field_strings() {
|
||||
indoc!(
|
||||
r#"
|
||||
app "test"
|
||||
imports [Encode.{ toEncoder }, Json]
|
||||
provides [main] to "./platform"
|
||||
|
||||
main =
|
||||
result = Str.fromUtf8 (Encode.toBytes {a: "foo", b: "bar"} Json.format)
|
||||
when result is
|
||||
Ok s -> s
|
||||
_ -> "<bad>"
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn encode_derived_nested_record_string() {
|
||||
indoc!(
|
||||
r#"
|
||||
app "test"
|
||||
imports [Encode.{ toEncoder }, Json]
|
||||
provides [main] to "./platform"
|
||||
|
||||
main =
|
||||
result = Str.fromUtf8 (Encode.toBytes {a: {b: "bar"}} Json.format)
|
||||
when result is
|
||||
Ok s -> s
|
||||
_ -> "<bad>"
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
#[ignore = "TODO make this work (one ULS var is missing)"]
|
||||
fn encode_derived_tag_one_field_string() {
|
||||
indoc!(
|
||||
r#"
|
||||
app "test"
|
||||
imports [Encode.{ toEncoder }, Json]
|
||||
provides [main] to "./platform"
|
||||
|
||||
main =
|
||||
x : [A Str]
|
||||
x = A "foo"
|
||||
result = Str.fromUtf8 (Encode.toBytes x Json.format)
|
||||
when result is
|
||||
Ok s -> s
|
||||
_ -> "<bad>"
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
|
|
@ -4666,6 +4666,7 @@ pub struct CopiedImport {
|
|||
|
||||
struct CopyImportEnv<'a> {
|
||||
visited: bumpalo::collections::Vec<'a, Variable>,
|
||||
/// source variable -> target variable
|
||||
copy_table: &'a mut VecMap<Variable, Variable>,
|
||||
source: &'a Subs,
|
||||
target: &'a mut Subs,
|
||||
|
|
|
@ -1062,12 +1062,12 @@ struct SeparatedUnionLambdas {
|
|||
joined: Vec<(Symbol, VariableSubsSlice)>,
|
||||
}
|
||||
|
||||
fn separate_union_lambdas(
|
||||
fn separate_union_lambdas<M: MetaCollector>(
|
||||
subs: &mut Subs,
|
||||
pool: &mut Pool,
|
||||
fields1: UnionLambdas,
|
||||
fields2: UnionLambdas,
|
||||
) -> SeparatedUnionLambdas {
|
||||
) -> (Outcome<M>, SeparatedUnionLambdas) {
|
||||
debug_assert!(
|
||||
fields1.is_sorted_allow_duplicates(subs),
|
||||
"not sorted: {:?}",
|
||||
|
@ -1124,6 +1124,7 @@ fn separate_union_lambdas(
|
|||
}
|
||||
}
|
||||
|
||||
let mut whole_outcome = Outcome::default();
|
||||
let mut only_in_left = Vec::with_capacity(fields1.len());
|
||||
let mut only_in_right = Vec::with_capacity(fields2.len());
|
||||
let mut joined = Vec::with_capacity(fields1.len() + fields2.len());
|
||||
|
@ -1172,13 +1173,14 @@ fn separate_union_lambdas(
|
|||
maybe_mark_union_recursive(subs, var1);
|
||||
maybe_mark_union_recursive(subs, var2);
|
||||
|
||||
let outcome =
|
||||
unify_pool::<NoCollector>(subs, pool, var1, var2, Mode::EQ);
|
||||
let outcome = unify_pool(subs, pool, var1, var2, Mode::EQ);
|
||||
|
||||
if !outcome.mismatches.is_empty() {
|
||||
subs.rollback_to(snapshot);
|
||||
continue 'try_next_right;
|
||||
}
|
||||
|
||||
whole_outcome.union(outcome);
|
||||
}
|
||||
|
||||
// All the variables unified, so we can join the left + right.
|
||||
|
@ -1202,11 +1204,14 @@ fn separate_union_lambdas(
|
|||
}
|
||||
}
|
||||
|
||||
SeparatedUnionLambdas {
|
||||
only_in_left,
|
||||
only_in_right,
|
||||
joined,
|
||||
}
|
||||
(
|
||||
whole_outcome,
|
||||
SeparatedUnionLambdas {
|
||||
only_in_left,
|
||||
only_in_right,
|
||||
joined,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn unify_unspecialized_lambdas<M: MetaCollector>(
|
||||
|
@ -1214,7 +1219,7 @@ fn unify_unspecialized_lambdas<M: MetaCollector>(
|
|||
pool: &mut Pool,
|
||||
uls1: SubsSlice<Uls>,
|
||||
uls2: SubsSlice<Uls>,
|
||||
) -> Result<SubsSlice<Uls>, Outcome<M>> {
|
||||
) -> Result<(SubsSlice<Uls>, Outcome<M>), Outcome<M>> {
|
||||
// For now we merge all variables of unspecialized lambdas in a lambda set that share the same
|
||||
// ability member/region.
|
||||
// See the section "A property that's lost, and how we can hold on to it" of
|
||||
|
@ -1225,9 +1230,9 @@ fn unify_unspecialized_lambdas<M: MetaCollector>(
|
|||
// resolves to itself or re-points to lset2.
|
||||
// In either case the merged unspecialized lambda sets will be there.
|
||||
match (uls1.is_empty(), uls2.is_empty()) {
|
||||
(true, true) => Ok(SubsSlice::default()),
|
||||
(false, true) => Ok(uls1),
|
||||
(true, false) => Ok(uls2),
|
||||
(true, true) => Ok((SubsSlice::default(), Default::default())),
|
||||
(false, true) => Ok((uls1, Default::default())),
|
||||
(true, false) => Ok((uls2, Default::default())),
|
||||
(false, false) => {
|
||||
let mut all_uls = (subs.get_subs_slice(uls1).iter())
|
||||
.chain(subs.get_subs_slice(uls2))
|
||||
|
@ -1241,6 +1246,7 @@ fn unify_unspecialized_lambdas<M: MetaCollector>(
|
|||
|
||||
// Now merge the variables of unspecialized lambdas pointing to the same
|
||||
// member/region.
|
||||
let mut whole_outcome = Outcome::default();
|
||||
let mut j = 1;
|
||||
while j < all_uls.len() {
|
||||
let i = j - 1;
|
||||
|
@ -1251,6 +1257,7 @@ fn unify_unspecialized_lambdas<M: MetaCollector>(
|
|||
if !outcome.mismatches.is_empty() {
|
||||
return Err(outcome);
|
||||
}
|
||||
whole_outcome.union(outcome);
|
||||
// Keep the Uls in position `i` and remove the one in position `j`.
|
||||
all_uls.remove(j);
|
||||
} else {
|
||||
|
@ -1259,9 +1266,9 @@ fn unify_unspecialized_lambdas<M: MetaCollector>(
|
|||
}
|
||||
}
|
||||
|
||||
Ok(SubsSlice::extend_new(
|
||||
&mut subs.unspecialized_lambda_sets,
|
||||
all_uls,
|
||||
Ok((
|
||||
SubsSlice::extend_new(&mut subs.unspecialized_lambda_sets, all_uls),
|
||||
whole_outcome,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -1302,11 +1309,14 @@ fn unify_lambda_set_help<M: MetaCollector>(
|
|||
"Recursion var is present, but it doesn't have a recursive content!"
|
||||
);
|
||||
|
||||
let SeparatedUnionLambdas {
|
||||
only_in_left,
|
||||
only_in_right,
|
||||
joined,
|
||||
} = separate_union_lambdas(subs, pool, solved1, solved2);
|
||||
let (
|
||||
mut whole_outcome,
|
||||
SeparatedUnionLambdas {
|
||||
only_in_left,
|
||||
only_in_right,
|
||||
joined,
|
||||
},
|
||||
) = separate_union_lambdas(subs, pool, solved1, solved2);
|
||||
|
||||
let all_lambdas = joined
|
||||
.into_iter()
|
||||
|
@ -1334,7 +1344,10 @@ fn unify_lambda_set_help<M: MetaCollector>(
|
|||
};
|
||||
|
||||
let merged_unspecialized = match unify_unspecialized_lambdas(subs, pool, uls1, uls2) {
|
||||
Ok(merged) => merged,
|
||||
Ok((merged, outcome)) => {
|
||||
whole_outcome.union(outcome);
|
||||
merged
|
||||
}
|
||||
Err(outcome) => {
|
||||
debug_assert!(!outcome.mismatches.is_empty());
|
||||
return outcome;
|
||||
|
@ -1349,7 +1362,9 @@ fn unify_lambda_set_help<M: MetaCollector>(
|
|||
ambient_function: ambient_function_var,
|
||||
});
|
||||
|
||||
merge(subs, ctx, new_lambda_set)
|
||||
let merge_outcome = merge(subs, ctx, new_lambda_set);
|
||||
whole_outcome.union(merge_outcome);
|
||||
whole_outcome
|
||||
}
|
||||
|
||||
/// Ensures that a non-recursive tag union, when unified with a recursion var to become a recursive
|
||||
|
@ -1882,6 +1897,8 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
let flat_type = FlatType::TagUnion(unique_tags1, ext1);
|
||||
let sub_record = fresh(subs, pool, ctx, Structure(flat_type));
|
||||
|
||||
let mut total_outcome = Outcome::default();
|
||||
|
||||
// In a presence context, we don't care about ext2 being equal to tags1
|
||||
if ctx.mode.is_eq() {
|
||||
let ext_outcome = unify_pool(subs, pool, sub_record, ext2, ctx.mode);
|
||||
|
@ -1889,9 +1906,10 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
if !ext_outcome.mismatches.is_empty() {
|
||||
return ext_outcome;
|
||||
}
|
||||
total_outcome.union(ext_outcome);
|
||||
}
|
||||
|
||||
unify_shared_tags_new(
|
||||
let shared_tags_outcome = unify_shared_tags_new(
|
||||
subs,
|
||||
pool,
|
||||
ctx,
|
||||
|
@ -1899,7 +1917,9 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
OtherTags2::Empty,
|
||||
sub_record,
|
||||
recursion_var,
|
||||
)
|
||||
);
|
||||
total_outcome.union(shared_tags_outcome);
|
||||
total_outcome
|
||||
} else {
|
||||
let other_tags = OtherTags2::Union(separate.only_in_1.clone(), separate.only_in_2.clone());
|
||||
|
||||
|
@ -1932,6 +1952,7 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
// without rolling back, the mismatch is between `[Blue, Red, Green]a` and `[Red, Green]`.
|
||||
// TODO is this also required for the other cases?
|
||||
|
||||
let mut total_outcome = Outcome::default();
|
||||
let snapshot = subs.snapshot();
|
||||
|
||||
let ext1_outcome = unify_pool(subs, pool, ext1, sub2, ctx.mode);
|
||||
|
@ -1939,6 +1960,7 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
subs.rollback_to(snapshot);
|
||||
return ext1_outcome;
|
||||
}
|
||||
total_outcome.union(ext1_outcome);
|
||||
|
||||
if ctx.mode.is_eq() {
|
||||
let ext2_outcome = unify_pool(subs, pool, sub1, ext2, ctx.mode);
|
||||
|
@ -1946,11 +1968,15 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
subs.rollback_to(snapshot);
|
||||
return ext2_outcome;
|
||||
}
|
||||
total_outcome.union(ext2_outcome);
|
||||
}
|
||||
|
||||
subs.commit_snapshot(snapshot);
|
||||
|
||||
unify_shared_tags_new(subs, pool, ctx, shared_tags, other_tags, ext, recursion_var)
|
||||
let shared_tags_outcome =
|
||||
unify_shared_tags_new(subs, pool, ctx, shared_tags, other_tags, ext, recursion_var);
|
||||
total_outcome.union(shared_tags_outcome);
|
||||
total_outcome
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -432,13 +432,9 @@ pub fn load_modules_for_files(filenames: Vec<PathBuf>) -> Vec<LoadedModule> {
|
|||
let mut modules = Vec::with_capacity(filenames.len());
|
||||
|
||||
for filename in filenames {
|
||||
let mut src_dir = filename.clone();
|
||||
src_dir.pop();
|
||||
|
||||
match roc_load::load_and_typecheck(
|
||||
&arena,
|
||||
filename,
|
||||
src_dir,
|
||||
Default::default(),
|
||||
roc_target::TargetInfo::default_x86_64(), // This is just type-checking for docs, so "target" doesn't matter
|
||||
roc_reporting::report::RenderTarget::ColorTerminal,
|
||||
|
|
|
@ -395,6 +395,8 @@ fn gen_and_eval_llvm<'a>(
|
|||
}
|
||||
};
|
||||
|
||||
let interns = loaded.interns.clone();
|
||||
|
||||
let (lib, main_fn_name, subs) =
|
||||
mono_module_to_dylib(&arena, target, loaded, opt_level).expect("we produce a valid Dylib");
|
||||
|
||||
|
@ -407,6 +409,7 @@ fn gen_and_eval_llvm<'a>(
|
|||
main_fn_layout,
|
||||
&content,
|
||||
&subs,
|
||||
&interns,
|
||||
target_info,
|
||||
);
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
use roc_types::types::AliasKind;
|
||||
use std::cmp::{max_by_key, min_by_key};
|
||||
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_module::called_via::CalledVia;
|
||||
use roc_module::ident::TagName;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use roc_mono::ir::ProcLayout;
|
||||
use roc_mono::layout::{
|
||||
union_sorted_tags_help, Builtin, Layout, LayoutCache, UnionLayout, UnionVariant, WrappedVariant,
|
||||
|
@ -23,6 +24,7 @@ struct Env<'a, 'env> {
|
|||
arena: &'a Bump,
|
||||
subs: &'env Subs,
|
||||
target_info: TargetInfo,
|
||||
interns: &'a Interns,
|
||||
}
|
||||
|
||||
pub enum ToAstProblem {
|
||||
|
@ -45,12 +47,14 @@ pub fn jit_to_ast<'a, A: ReplApp<'a>>(
|
|||
layout: ProcLayout<'a>,
|
||||
content: &'a Content,
|
||||
subs: &'a Subs,
|
||||
interns: &'a Interns,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<Expr<'a>, ToAstProblem> {
|
||||
let env = Env {
|
||||
arena,
|
||||
subs,
|
||||
target_info,
|
||||
interns,
|
||||
};
|
||||
|
||||
match layout {
|
||||
|
@ -70,6 +74,7 @@ pub fn jit_to_ast<'a, A: ReplApp<'a>>(
|
|||
enum NewtypeKind<'a> {
|
||||
Tag(&'a TagName),
|
||||
RecordField(&'a str),
|
||||
Opaque(Symbol),
|
||||
}
|
||||
|
||||
/// Unrolls types that are newtypes. These include
|
||||
|
@ -115,7 +120,7 @@ fn unroll_newtypes_and_aliases<'a>(
|
|||
));
|
||||
content = env.subs.get_content_without_compacting(field.into_inner());
|
||||
}
|
||||
Content::Alias(_, _, real_var, _) => {
|
||||
Content::Alias(name, _, real_var, kind) => {
|
||||
// We need to pass through aliases too, because their underlying types may have
|
||||
// unrolled newtypes. For example,
|
||||
// T : { a : Str }
|
||||
|
@ -126,6 +131,9 @@ fn unroll_newtypes_and_aliases<'a>(
|
|||
//
|
||||
// At the end of the day what we should show to the user is the alias content, not
|
||||
// what's inside, so keep that around too.
|
||||
if *kind == AliasKind::Opaque && name.module_id() != ModuleId::NUM {
|
||||
newtype_containers.push(NewtypeKind::Opaque(*name));
|
||||
}
|
||||
alias_content = Some(content);
|
||||
content = env.subs.get_content_without_compacting(*real_var);
|
||||
}
|
||||
|
@ -157,6 +165,13 @@ fn apply_newtypes<'a>(
|
|||
let field = Loc::at_zero(AssignedField::RequiredValue(label, &[], field_val));
|
||||
expr = Expr::Record(Collection::with_items(&*arena.alloc([field])))
|
||||
}
|
||||
NewtypeKind::Opaque(name) => {
|
||||
let opaque_name = arena.alloc(format!("@{}", name.as_str(env.interns)));
|
||||
let opaque_ref = &*arena.alloc(Loc::at_zero(Expr::OpaqueRef(opaque_name)));
|
||||
let loc_arg_expr = &*arena.alloc(Loc::at_zero(expr));
|
||||
let loc_arg_exprs = arena.alloc_slice_copy(&[loc_arg_expr]);
|
||||
expr = Expr::Apply(opaque_ref, loc_arg_exprs, CalledVia::Space);
|
||||
}
|
||||
}
|
||||
}
|
||||
expr
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use roc_module::symbol::Interns;
|
||||
use roc_mono::{
|
||||
ir::ProcLayout,
|
||||
layout::{CapturesNiche, LayoutCache},
|
||||
|
@ -16,6 +17,7 @@ pub fn get_values<'a>(
|
|||
target_info: TargetInfo,
|
||||
arena: &'a bumpalo::Bump,
|
||||
subs: &'a Subs,
|
||||
interns: &'a Interns,
|
||||
start: *const u8,
|
||||
mut start_offset: usize,
|
||||
variables: &[Variable],
|
||||
|
@ -52,6 +54,7 @@ pub fn get_values<'a>(
|
|||
proc_layout,
|
||||
content,
|
||||
subs,
|
||||
interns,
|
||||
target_info,
|
||||
)
|
||||
}?;
|
||||
|
|
|
@ -1024,7 +1024,7 @@ fn opaque_apply() {
|
|||
@Age 23
|
||||
"#
|
||||
),
|
||||
"23 : Age",
|
||||
"@Age 23 : Age",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1038,7 +1038,7 @@ fn opaque_apply_polymorphic() {
|
|||
@F (Package "" { a: "" })
|
||||
"#
|
||||
),
|
||||
r#"Package "" { a: "" } : F Str { a : Str }"#,
|
||||
r#"@F (Package "" { a: "" }) : F Str { a : Str }"#,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1054,7 +1054,7 @@ fn opaque_pattern_and_call() {
|
|||
f (@F (Package A {}))
|
||||
"#
|
||||
),
|
||||
r#"Package {} A : F {} [A]*"#,
|
||||
r#"@F (Package {} A) : F {} [A]*"#,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1189,6 +1189,6 @@ fn opaque_wrap_function() {
|
|||
List.map [1u8, 2u8, 3u8] @A
|
||||
"#
|
||||
),
|
||||
"[1, 2, 3] : List (A U8)",
|
||||
"[@A 1, @A 2, @A 3] : List (A U8)",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -251,6 +251,7 @@ pub async fn entrypoint_from_js(src: String) -> Result<String, String> {
|
|||
main_fn_layout,
|
||||
content,
|
||||
&subs,
|
||||
&interns,
|
||||
target_info,
|
||||
);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ bumpalo = { version = "3.8.0", features = ["collections"] }
|
|||
|
||||
[dev-dependencies]
|
||||
roc_constrain = { path = "../compiler/constrain" }
|
||||
roc_derive_key = { path = "../compiler/derive_key" }
|
||||
roc_derive = { path = "../compiler/derive" }
|
||||
roc_builtins = { path = "../compiler/builtins" }
|
||||
roc_load = { path = "../compiler/load" }
|
||||
roc_problem = { path = "../compiler/problem" }
|
||||
|
|
|
@ -10,7 +10,7 @@ use roc_can::operator;
|
|||
use roc_can::scope::Scope;
|
||||
use roc_collections::all::{ImMap, MutMap, SendSet};
|
||||
use roc_constrain::expr::constrain_expr;
|
||||
use roc_derive_key::GlobalDerivedSymbols;
|
||||
use roc_derive::SharedDerivedModule;
|
||||
use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds};
|
||||
use roc_parse::parser::{SourceError, SyntaxError};
|
||||
use roc_problem::can::Problem;
|
||||
|
@ -35,10 +35,11 @@ pub fn infer_expr(
|
|||
pending_derives: PendingDerives,
|
||||
aliases: &mut Aliases,
|
||||
abilities_store: &mut AbilitiesStore,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
derived_module: SharedDerivedModule,
|
||||
expr_var: Variable,
|
||||
) -> (Content, Subs) {
|
||||
let (solved, _) = solve::run(
|
||||
ModuleId::ATTR,
|
||||
constraints,
|
||||
problems,
|
||||
subs,
|
||||
|
@ -46,7 +47,8 @@ pub fn infer_expr(
|
|||
constraint,
|
||||
pending_derives,
|
||||
abilities_store,
|
||||
derived_symbols,
|
||||
&Default::default(),
|
||||
derived_module,
|
||||
);
|
||||
|
||||
let content = *solved.inner().get_content_without_compacting(expr_var);
|
||||
|
|
|
@ -86,7 +86,6 @@ mod test_reporting {
|
|||
let result = roc_load::load_and_typecheck(
|
||||
arena,
|
||||
full_file_path,
|
||||
dir.path().to_path_buf(),
|
||||
exposed_types,
|
||||
roc_target::TargetInfo::default_x86_64(),
|
||||
RenderTarget::Generic,
|
||||
|
@ -9055,39 +9054,6 @@ All branches in an `if` must have the same type!
|
|||
"#
|
||||
);
|
||||
|
||||
test_report!(
|
||||
unbound_type_in_record_does_not_implement_encoding,
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" imports [Encode] provides [main] to "./platform"
|
||||
|
||||
main = \x -> Encode.toEncoder { x: x }
|
||||
"#
|
||||
),
|
||||
@r#"
|
||||
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
This expression has a type that does not implement the abilities it's expected to:
|
||||
|
||||
3│ main = \x -> Encode.toEncoder { x: x }
|
||||
^^^^^^^^
|
||||
|
||||
Roc can't generate an implementation of the `Encode.Encoding` ability
|
||||
for
|
||||
|
||||
{ x : a }
|
||||
|
||||
In particular, an implementation for
|
||||
|
||||
a
|
||||
|
||||
cannot be generated.
|
||||
|
||||
Tip: This type variable is not bound to `Encoding`. Consider adding a
|
||||
`has` clause to bind the type variable, like `| a has Encode.Encoding`
|
||||
"#
|
||||
);
|
||||
|
||||
test_report!(
|
||||
nested_opaque_does_not_implement_encoding,
|
||||
indoc!(
|
||||
|
@ -9098,7 +9064,9 @@ All branches in an `if` must have the same type!
|
|||
main = Encode.toEncoder { x: @A {} }
|
||||
"#
|
||||
),
|
||||
@r#"
|
||||
// TODO: this error message is quite unfortunate. We should remove the duplication, and
|
||||
// also support regions that point to things in other modules. See also https://github.com/rtfeldman/roc/issues/3056.
|
||||
@r###"
|
||||
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
This expression has a type that does not implement the abilities it's expected to:
|
||||
|
@ -9119,7 +9087,17 @@ All branches in an `if` must have the same type!
|
|||
|
||||
Tip: `A` does not implement `Encoding`. Consider adding a custom
|
||||
implementation or `has Encode.Encoding` to the definition of `A`.
|
||||
"#
|
||||
|
||||
── INCOMPLETE ABILITY IMPLEMENTATION ───────────────────── /code/proj/Main.roc ─
|
||||
|
||||
The type `A` does not fully implement the ability `Encoding`. The
|
||||
following specializations are missing:
|
||||
|
||||
A specialization for `toEncoder`, which is defined here:
|
||||
|
||||
5│
|
||||
^^^^^^^^^
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
interface InternalTask
|
||||
exposes [Task, fromEffect, toEffect]
|
||||
imports [pf.Effect.{ Effect }]
|
||||
imports [Effect.{ Effect }]
|
||||
|
||||
Task ok err fx := Effect (Result ok err)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
interface Task
|
||||
exposes [Task, succeed, fail, await, map, onFail, attempt, forever, loop]
|
||||
imports [pf.Effect, pf.InternalTask]
|
||||
imports [Effect, InternalTask]
|
||||
|
||||
Task ok err fx : InternalTask.Task ok err fx
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue