mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-02 19:32:17 +00:00
Merge remote-tracking branch 'origin/main' into packages
This commit is contained in:
commit
3e448fd2b4
61 changed files with 1506 additions and 538 deletions
9
.github/workflows/nightly_macos_x86_64.yml
vendored
9
.github/workflows/nightly_macos_x86_64.yml
vendored
|
@ -15,16 +15,15 @@ jobs:
|
||||||
- name: write version to file
|
- name: write version to file
|
||||||
run: ./ci/write_version.sh
|
run: ./ci/write_version.sh
|
||||||
|
|
||||||
# build has to be done before tests #2572
|
|
||||||
- name: build release
|
|
||||||
run: RUSTFLAGS="-C target-cpu=x86-64" cargo build --features with_sound --release --locked
|
|
||||||
# target-cpu=x86-64 -> For maximal compatibility for all CPU's. Note that this setting will likely make the compiler slower.
|
|
||||||
|
|
||||||
- name: execute rust tests
|
- name: execute rust tests
|
||||||
run: cargo test --release --locked -- --skip opaque_wrap_function --skip bool_list_literal --skip platform_switching_swift --skip swift_ui
|
run: cargo test --release --locked -- --skip opaque_wrap_function --skip bool_list_literal --skip platform_switching_swift --skip swift_ui
|
||||||
# swift tests are skipped because of "Could not find or use auto-linked library 'swiftCompatibilityConcurrency'" on macos-11 x86_64 CI machine
|
# swift tests are skipped because of "Could not find or use auto-linked library 'swiftCompatibilityConcurrency'" on macos-11 x86_64 CI machine
|
||||||
# this issue may be caused by using older versions of XCode
|
# this issue may be caused by using older versions of XCode
|
||||||
|
|
||||||
|
- name: build release
|
||||||
|
run: RUSTFLAGS="-C target-cpu=x86-64" cargo build --features with_sound --release --locked
|
||||||
|
# target-cpu=x86-64 -> For maximal compatibility for all CPU's. Note that this setting will likely make the compiler slower.
|
||||||
|
|
||||||
- name: get commit SHA
|
- name: get commit SHA
|
||||||
run: echo "SHA=$(git rev-parse --short "$GITHUB_SHA")" >> $GITHUB_ENV
|
run: echo "SHA=$(git rev-parse --short "$GITHUB_SHA")" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
|
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3700,6 +3700,7 @@ dependencies = [
|
||||||
"roc_serialize",
|
"roc_serialize",
|
||||||
"roc_types",
|
"roc_types",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
|
"ven_pretty",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -39,6 +39,8 @@ target-all = [
|
||||||
"target-wasm32"
|
"target-wasm32"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
sanitizers = ["roc_build/sanitizers"]
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
roc_collections = { path = "../compiler/collections" }
|
roc_collections = { path = "../compiler/collections" }
|
||||||
|
|
|
@ -186,7 +186,9 @@ pub fn build_file<'a>(
|
||||||
};
|
};
|
||||||
|
|
||||||
// We don't need to spawn a rebuild thread when using a prebuilt host.
|
// We don't need to spawn a rebuild thread when using a prebuilt host.
|
||||||
let rebuild_thread = if is_prebuilt {
|
let rebuild_thread = if matches!(link_type, LinkType::Dylib | LinkType::None) {
|
||||||
|
None
|
||||||
|
} else if is_prebuilt {
|
||||||
if !preprocessed_host_path.exists() {
|
if !preprocessed_host_path.exists() {
|
||||||
if prebuilt_requested {
|
if prebuilt_requested {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
|
@ -378,10 +380,11 @@ pub fn build_file<'a>(
|
||||||
|
|
||||||
std::fs::write(app_o_file, &*roc_app_bytes).unwrap();
|
std::fs::write(app_o_file, &*roc_app_bytes).unwrap();
|
||||||
|
|
||||||
let mut inputs = vec![
|
let mut inputs = vec![app_o_file.to_str().unwrap()];
|
||||||
host_input_path.as_path().to_str().unwrap(),
|
|
||||||
app_o_file.to_str().unwrap(),
|
if !matches!(link_type, LinkType::Dylib | LinkType::None) {
|
||||||
];
|
inputs.push(host_input_path.as_path().to_str().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
let builtins_host_tempfile = {
|
let builtins_host_tempfile = {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
|
|
@ -568,7 +568,7 @@ mod cli_run {
|
||||||
r#"
|
r#"
|
||||||
This expectation failed:
|
This expectation failed:
|
||||||
|
|
||||||
14│ expect x != x
|
18│ expect x != x
|
||||||
^^^^^^
|
^^^^^^
|
||||||
|
|
||||||
When it failed, these variables had these values:
|
When it failed, these variables had these values:
|
||||||
|
@ -576,8 +576,11 @@ mod cli_run {
|
||||||
x : Num *
|
x : Num *
|
||||||
x = 42
|
x = 42
|
||||||
|
|
||||||
[<ignored for tests> 15:9] 42
|
[<ignored for tests> 19:9] 42
|
||||||
[<ignored for tests> 16:9] "Fjoer en ferdjer frieten oan dyn geve lea"
|
[<ignored for tests> 20:9] "Fjoer en ferdjer frieten oan dyn geve lea"
|
||||||
|
[<ignored for tests> 13:9] "abc"
|
||||||
|
[<ignored for tests> 13:9] 10
|
||||||
|
[<ignored for tests> 13:9] A (B C)
|
||||||
Program finished!
|
Program finished!
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
|
|
@ -9,9 +9,17 @@ expect
|
||||||
|
|
||||||
a == b
|
a == b
|
||||||
|
|
||||||
|
polyDbg = \x ->
|
||||||
|
dbg x
|
||||||
|
x
|
||||||
|
|
||||||
main =
|
main =
|
||||||
x = 42
|
x = 42
|
||||||
expect x != x
|
expect x != x
|
||||||
dbg x
|
dbg x
|
||||||
dbg "Fjoer en ferdjer frieten oan dyn geve lea"
|
dbg "Fjoer en ferdjer frieten oan dyn geve lea"
|
||||||
"Program finished!\n"
|
|
||||||
|
r = {x : polyDbg "abc", y: polyDbg 10u8, z : polyDbg (A (B C))}
|
||||||
|
|
||||||
|
when r is
|
||||||
|
_ -> "Program finished!\n"
|
||||||
|
|
|
@ -1287,6 +1287,14 @@ fn lowlevel_spec<'a>(
|
||||||
|
|
||||||
builder.add_make_tuple(block, &[byte_index, string, is_ok, problem_code])
|
builder.add_make_tuple(block, &[byte_index, string, is_ok, problem_code])
|
||||||
}
|
}
|
||||||
|
Dbg => {
|
||||||
|
let arguments = [env.symbols[&arguments[0]]];
|
||||||
|
|
||||||
|
let result_type =
|
||||||
|
layout_spec(env, builder, interner, layout, &WhenRecursive::Unreachable)?;
|
||||||
|
|
||||||
|
builder.add_unknown_with(block, &arguments, result_type)
|
||||||
|
}
|
||||||
_other => {
|
_other => {
|
||||||
// println!("missing {:?}", _other);
|
// println!("missing {:?}", _other);
|
||||||
// TODO overly pessimstic
|
// TODO overly pessimstic
|
||||||
|
|
|
@ -47,3 +47,7 @@ target-aarch64 = ["roc_gen_dev/target-aarch64"]
|
||||||
target-x86 = []
|
target-x86 = []
|
||||||
target-x86_64 = ["roc_gen_dev/target-x86_64"]
|
target-x86_64 = ["roc_gen_dev/target-x86_64"]
|
||||||
target-wasm32 = []
|
target-wasm32 = []
|
||||||
|
|
||||||
|
# This is used to enable fuzzing and sanitizers.
|
||||||
|
# Example use is describe here: https://github.com/bhansconnect/roc-fuzz
|
||||||
|
sanitizers = []
|
||||||
|
|
|
@ -1248,14 +1248,17 @@ fn link_macos(
|
||||||
input_paths: &[&str],
|
input_paths: &[&str],
|
||||||
link_type: LinkType,
|
link_type: LinkType,
|
||||||
) -> io::Result<(Child, PathBuf)> {
|
) -> io::Result<(Child, PathBuf)> {
|
||||||
let (link_type_arg, output_path) = match link_type {
|
let (link_type_args, output_path) = match link_type {
|
||||||
LinkType::Executable => ("-execute", output_path),
|
LinkType::Executable => (vec!["-execute"], output_path),
|
||||||
LinkType::Dylib => {
|
LinkType::Dylib => {
|
||||||
let mut output_path = output_path;
|
let mut output_path = output_path;
|
||||||
|
|
||||||
output_path.set_extension("dylib");
|
output_path.set_extension("dylib");
|
||||||
|
|
||||||
("-dylib", output_path)
|
(
|
||||||
|
vec!["-dylib", "-undefined", "dynamic_lookup", "-no_fixup_chains"],
|
||||||
|
output_path,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
LinkType::None => internal_error!("link_macos should not be called with link type of none"),
|
LinkType::None => internal_error!("link_macos should not be called with link type of none"),
|
||||||
};
|
};
|
||||||
|
@ -1272,13 +1275,13 @@ fn link_macos(
|
||||||
// The `-l` flags should go after the `.o` arguments
|
// The `-l` flags should go after the `.o` arguments
|
||||||
// Don't allow LD_ env vars to affect this
|
// Don't allow LD_ env vars to affect this
|
||||||
.env_clear()
|
.env_clear()
|
||||||
|
.args(&link_type_args)
|
||||||
.args([
|
.args([
|
||||||
// NOTE: we don't do --gc-sections on macOS because the default
|
// NOTE: we don't do --gc-sections on macOS because the default
|
||||||
// macOS linker doesn't support it, but it's a performance
|
// macOS linker doesn't support it, but it's a performance
|
||||||
// optimization, so if we ever switch to a different linker,
|
// optimization, so if we ever switch to a different linker,
|
||||||
// we'd like to re-enable it on macOS!
|
// we'd like to re-enable it on macOS!
|
||||||
// "--gc-sections",
|
// "--gc-sections",
|
||||||
link_type_arg,
|
|
||||||
"-arch",
|
"-arch",
|
||||||
&arch,
|
&arch,
|
||||||
"-macos_version_min",
|
"-macos_version_min",
|
||||||
|
|
|
@ -237,15 +237,94 @@ fn gen_from_mono_module_llvm<'a>(
|
||||||
|
|
||||||
// annotate the LLVM IR output with debug info
|
// annotate the LLVM IR output with debug info
|
||||||
// so errors are reported with the line number of the LLVM source
|
// so errors are reported with the line number of the LLVM source
|
||||||
let memory_buffer = if emit_debug_info {
|
let memory_buffer = if cfg!(feature = "sanitizers") && std::env::var("ROC_SANITIZERS").is_ok() {
|
||||||
|
let dir = tempfile::tempdir().unwrap();
|
||||||
|
let dir = dir.into_path();
|
||||||
|
|
||||||
|
let app_ll_file = dir.join("app.ll");
|
||||||
|
let app_bc_file = dir.join("app.bc");
|
||||||
|
let app_o_file = dir.join("app.o");
|
||||||
|
|
||||||
|
// write the ll code to a file, so we can modify it
|
||||||
|
module.print_to_file(&app_ll_file).unwrap();
|
||||||
|
|
||||||
|
// Apply coverage passes.
|
||||||
|
// Note, this is specifically tailored for `cargo afl` and afl++.
|
||||||
|
// It most likely will not work with other fuzzer setups without modification.
|
||||||
|
let mut passes = vec![];
|
||||||
|
let mut extra_args = vec![];
|
||||||
|
let mut unrecognized = vec![];
|
||||||
|
for sanitizer in std::env::var("ROC_SANITIZERS")
|
||||||
|
.unwrap()
|
||||||
|
.split(',')
|
||||||
|
.map(|x| x.trim())
|
||||||
|
{
|
||||||
|
match sanitizer {
|
||||||
|
"address" => passes.push("asan-module"),
|
||||||
|
"memory" => passes.push("msan-module"),
|
||||||
|
"thread" => passes.push("tsan-module"),
|
||||||
|
"fuzzer" => {
|
||||||
|
passes.push("sancov-module");
|
||||||
|
extra_args.extend_from_slice(&[
|
||||||
|
"-sanitizer-coverage-level=3",
|
||||||
|
"-sanitizer-coverage-prune-blocks=0",
|
||||||
|
"-sanitizer-coverage-trace-pc-guard",
|
||||||
|
// This can be used instead of the line above to enable working with `cargo fuzz` and libFuzzer.
|
||||||
|
// "-sanitizer-coverage-inline-8bit-counters",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
x => unrecognized.push(x.to_owned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !unrecognized.is_empty() {
|
||||||
|
let out = unrecognized
|
||||||
|
.iter()
|
||||||
|
.map(|x| format!("{:?}", x))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(", ");
|
||||||
|
eprintln!("Unrecognized sanitizer: {}\nSupported options are \"address\", \"memory\", \"thread\", and \"fuzzer\"", out);
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::process::Command;
|
||||||
|
let mut opt = Command::new("opt");
|
||||||
|
opt.args([
|
||||||
|
app_ll_file.to_str().unwrap(),
|
||||||
|
"-o",
|
||||||
|
app_bc_file.to_str().unwrap(),
|
||||||
|
])
|
||||||
|
.args(extra_args);
|
||||||
|
if !passes.is_empty() {
|
||||||
|
opt.arg(format!("-passes={}", passes.join(",")));
|
||||||
|
}
|
||||||
|
let opt = opt.output().unwrap();
|
||||||
|
|
||||||
|
assert!(opt.stderr.is_empty(), "{:#?}", opt);
|
||||||
|
|
||||||
|
// write the .o file. Note that this builds the .o for the local machine,
|
||||||
|
// and ignores the `target_machine` entirely.
|
||||||
|
//
|
||||||
|
// different systems name this executable differently, so we shotgun for
|
||||||
|
// the most common ones and then give up.
|
||||||
|
let bc_to_object = Command::new("llc")
|
||||||
|
.args(&[
|
||||||
|
"-relocation-model=pic",
|
||||||
|
"-filetype=obj",
|
||||||
|
app_bc_file.to_str().unwrap(),
|
||||||
|
"-o",
|
||||||
|
app_o_file.to_str().unwrap(),
|
||||||
|
])
|
||||||
|
.output()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(bc_to_object.status.success(), "{:#?}", bc_to_object);
|
||||||
|
|
||||||
|
MemoryBuffer::create_from_file(&app_o_file).expect("memory buffer creation works")
|
||||||
|
} else if emit_debug_info {
|
||||||
module.strip_debug_info();
|
module.strip_debug_info();
|
||||||
|
|
||||||
let mut app_ll_dbg_file = PathBuf::from(roc_file_path);
|
let mut app_ll_dbg_file = PathBuf::from(roc_file_path);
|
||||||
app_ll_dbg_file.set_extension("dbg.ll");
|
app_ll_dbg_file.set_extension("dbg.ll");
|
||||||
|
|
||||||
let mut app_bc_file = PathBuf::from(roc_file_path);
|
|
||||||
app_bc_file.set_extension("bc");
|
|
||||||
|
|
||||||
let mut app_o_file = PathBuf::from(roc_file_path);
|
let mut app_o_file = PathBuf::from(roc_file_path);
|
||||||
app_o_file.set_extension("o");
|
app_o_file.set_extension("o");
|
||||||
|
|
||||||
|
@ -277,33 +356,23 @@ fn gen_from_mono_module_llvm<'a>(
|
||||||
| Architecture::X86_32(_)
|
| Architecture::X86_32(_)
|
||||||
| Architecture::Aarch64(_)
|
| Architecture::Aarch64(_)
|
||||||
| Architecture::Wasm32 => {
|
| Architecture::Wasm32 => {
|
||||||
let ll_to_bc = Command::new("llvm-as")
|
|
||||||
.args([
|
|
||||||
app_ll_dbg_file.to_str().unwrap(),
|
|
||||||
"-o",
|
|
||||||
app_bc_file.to_str().unwrap(),
|
|
||||||
])
|
|
||||||
.output()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert!(ll_to_bc.stderr.is_empty(), "{:#?}", ll_to_bc);
|
|
||||||
|
|
||||||
let llc_args = &[
|
|
||||||
"-relocation-model=pic",
|
|
||||||
"-filetype=obj",
|
|
||||||
app_bc_file.to_str().unwrap(),
|
|
||||||
"-o",
|
|
||||||
app_o_file.to_str().unwrap(),
|
|
||||||
];
|
|
||||||
|
|
||||||
// write the .o file. Note that this builds the .o for the local machine,
|
// write the .o file. Note that this builds the .o for the local machine,
|
||||||
// and ignores the `target_machine` entirely.
|
// and ignores the `target_machine` entirely.
|
||||||
//
|
//
|
||||||
// different systems name this executable differently, so we shotgun for
|
// different systems name this executable differently, so we shotgun for
|
||||||
// the most common ones and then give up.
|
// the most common ones and then give up.
|
||||||
let bc_to_object = Command::new("llc").args(llc_args).output().unwrap();
|
let ll_to_object = Command::new("llc")
|
||||||
|
.args(&[
|
||||||
|
"-relocation-model=pic",
|
||||||
|
"-filetype=obj",
|
||||||
|
app_ll_dbg_file.to_str().unwrap(),
|
||||||
|
"-o",
|
||||||
|
app_o_file.to_str().unwrap(),
|
||||||
|
])
|
||||||
|
.output()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(bc_to_object.stderr.is_empty(), "{:#?}", bc_to_object);
|
assert!(ll_to_object.stderr.is_empty(), "{:#?}", ll_to_object);
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,6 @@ pub enum DecWidth {
|
||||||
pub enum FloatWidth {
|
pub enum FloatWidth {
|
||||||
F32,
|
F32,
|
||||||
F64,
|
F64,
|
||||||
F128,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FloatWidth {
|
impl FloatWidth {
|
||||||
|
@ -86,7 +85,6 @@ impl FloatWidth {
|
||||||
match self {
|
match self {
|
||||||
F32 => 4,
|
F32 => 4,
|
||||||
F64 => 8,
|
F64 => 8,
|
||||||
F128 => 16,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +97,7 @@ impl FloatWidth {
|
||||||
// the compiler is targeting (e.g. what the Roc code will be compiled to).
|
// the compiler is targeting (e.g. what the Roc code will be compiled to).
|
||||||
match self {
|
match self {
|
||||||
F32 => 4,
|
F32 => 4,
|
||||||
F64 | F128 => match target_info.architecture {
|
F64 => match target_info.architecture {
|
||||||
X86_64 | Aarch64 | Wasm32 => 8,
|
X86_64 | Aarch64 | Wasm32 => 8,
|
||||||
X86_32 | Aarch32 => 4,
|
X86_32 | Aarch32 => 4,
|
||||||
},
|
},
|
||||||
|
@ -225,7 +223,6 @@ impl Index<FloatWidth> for IntrinsicName {
|
||||||
match index {
|
match index {
|
||||||
FloatWidth::F32 => self.options[1],
|
FloatWidth::F32 => self.options[1],
|
||||||
FloatWidth::F64 => self.options[2],
|
FloatWidth::F64 => self.options[2],
|
||||||
FloatWidth::F128 => self.options[3],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,7 +253,6 @@ macro_rules! float_intrinsic {
|
||||||
|
|
||||||
output.options[1] = concat!($name, ".f32");
|
output.options[1] = concat!($name, ".f32");
|
||||||
output.options[2] = concat!($name, ".f64");
|
output.options[2] = concat!($name, ".f64");
|
||||||
output.options[3] = concat!($name, ".f128");
|
|
||||||
|
|
||||||
output
|
output
|
||||||
}};
|
}};
|
||||||
|
|
|
@ -21,6 +21,8 @@ bumpalo.workspace = true
|
||||||
static_assertions.workspace = true
|
static_assertions.workspace = true
|
||||||
bitvec.workspace = true
|
bitvec.workspace = true
|
||||||
|
|
||||||
|
ven_pretty = { path = "../../vendor/pretty" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions.workspace = true
|
pretty_assertions.workspace = true
|
||||||
indoc.workspace = true
|
indoc.workspace = true
|
||||||
|
|
5
crates/compiler/can/src/debug.rs
Normal file
5
crates/compiler/can/src/debug.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
mod pretty_print;
|
||||||
|
|
||||||
|
pub use pretty_print::pretty_print_declarations;
|
||||||
|
pub use pretty_print::pretty_print_def;
|
||||||
|
pub use pretty_print::Ctx as PPCtx;
|
|
@ -1,16 +1,50 @@
|
||||||
//! Pretty-prints the canonical AST back to check our work - do things look reasonable?
|
//! Pretty-prints the canonical AST back to check our work - do things look reasonable?
|
||||||
|
|
||||||
use roc_can::def::Def;
|
use crate::def::Def;
|
||||||
use roc_can::expr::Expr::{self, *};
|
use crate::expr::Expr::{self, *};
|
||||||
use roc_can::expr::{ClosureData, OpaqueWrapFunctionData, WhenBranch};
|
use crate::expr::{
|
||||||
use roc_can::pattern::{Pattern, RecordDestruct};
|
ClosureData, DeclarationTag, Declarations, FunctionDef, OpaqueWrapFunctionData, WhenBranch,
|
||||||
|
};
|
||||||
|
use crate::pattern::{Pattern, RecordDestruct};
|
||||||
|
|
||||||
use roc_module::symbol::Interns;
|
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||||
|
|
||||||
use ven_pretty::{Arena, DocAllocator, DocBuilder};
|
use ven_pretty::{Arena, DocAllocator, DocBuilder};
|
||||||
|
|
||||||
pub struct Ctx<'a> {
|
pub struct Ctx<'a> {
|
||||||
|
pub home: ModuleId,
|
||||||
pub interns: &'a Interns,
|
pub interns: &'a Interns,
|
||||||
|
pub print_lambda_names: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pretty_print_declarations(c: &Ctx, declarations: &Declarations) -> String {
|
||||||
|
let f = Arena::new();
|
||||||
|
let mut defs = Vec::with_capacity(declarations.len());
|
||||||
|
for (index, tag) in declarations.iter_bottom_up() {
|
||||||
|
let symbol = declarations.symbols[index].value;
|
||||||
|
let body = &declarations.expressions[index];
|
||||||
|
|
||||||
|
let def = match tag {
|
||||||
|
DeclarationTag::Value => def_symbol_help(c, &f, symbol, &body.value),
|
||||||
|
DeclarationTag::Function(f_index)
|
||||||
|
| DeclarationTag::Recursive(f_index)
|
||||||
|
| DeclarationTag::TailRecursive(f_index) => {
|
||||||
|
let function_def = &declarations.function_bodies[f_index.index()].value;
|
||||||
|
toplevel_function(c, &f, symbol, function_def, &body.value)
|
||||||
|
}
|
||||||
|
DeclarationTag::Expectation => todo!(),
|
||||||
|
DeclarationTag::ExpectationFx => todo!(),
|
||||||
|
DeclarationTag::Destructure(_) => todo!(),
|
||||||
|
DeclarationTag::MutualRecursion { .. } => todo!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
defs.push(def);
|
||||||
|
}
|
||||||
|
|
||||||
|
f.intersperse(defs, f.hardline().append(f.hardline()))
|
||||||
|
.1
|
||||||
|
.pretty(80)
|
||||||
|
.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pretty_print_def(c: &Ctx, d: &Def) -> String {
|
pub fn pretty_print_def(c: &Ctx, d: &Def) -> String {
|
||||||
|
@ -40,10 +74,58 @@ fn def<'a>(c: &Ctx, f: &'a Arena<'a>, d: &'a Def) -> DocBuilder<'a, Arena<'a>> {
|
||||||
annotation: _,
|
annotation: _,
|
||||||
} = d;
|
} = d;
|
||||||
|
|
||||||
pattern(c, PPrec::Free, f, &loc_pattern.value)
|
def_help(c, f, &loc_pattern.value, &loc_expr.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn def_symbol_help<'a>(
|
||||||
|
c: &Ctx,
|
||||||
|
f: &'a Arena<'a>,
|
||||||
|
sym: Symbol,
|
||||||
|
body: &'a Expr,
|
||||||
|
) -> DocBuilder<'a, Arena<'a>> {
|
||||||
|
pp_sym(c, f, sym)
|
||||||
.append(f.text(" ="))
|
.append(f.text(" ="))
|
||||||
.append(f.line())
|
.append(f.line())
|
||||||
.append(expr(c, EPrec::Free, f, &loc_expr.value))
|
.append(expr(c, EPrec::Free, f, body))
|
||||||
|
.nest(2)
|
||||||
|
.group()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn def_help<'a>(
|
||||||
|
c: &Ctx,
|
||||||
|
f: &'a Arena<'a>,
|
||||||
|
pat: &'a Pattern,
|
||||||
|
body: &'a Expr,
|
||||||
|
) -> DocBuilder<'a, Arena<'a>> {
|
||||||
|
pattern(c, PPrec::Free, f, pat)
|
||||||
|
.append(f.text(" ="))
|
||||||
|
.append(f.line())
|
||||||
|
.append(expr(c, EPrec::Free, f, body))
|
||||||
|
.nest(2)
|
||||||
|
.group()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toplevel_function<'a>(
|
||||||
|
c: &Ctx,
|
||||||
|
f: &'a Arena<'a>,
|
||||||
|
sym: Symbol,
|
||||||
|
function_def: &'a FunctionDef,
|
||||||
|
body: &'a Expr,
|
||||||
|
) -> DocBuilder<'a, Arena<'a>> {
|
||||||
|
let FunctionDef { arguments, .. } = function_def;
|
||||||
|
|
||||||
|
let args = arguments
|
||||||
|
.iter()
|
||||||
|
.map(|arg| pattern(c, PPrec::Free, f, &arg.2.value));
|
||||||
|
|
||||||
|
pp_sym(c, f, sym)
|
||||||
|
.append(f.text(" ="))
|
||||||
|
.append(f.line())
|
||||||
|
.append(f.text("\\"))
|
||||||
|
.append(f.intersperse(args, f.text(", ")))
|
||||||
|
.append(f.text("->"))
|
||||||
|
.append(f.line())
|
||||||
|
.append(expr(c, EPrec::Free, f, body))
|
||||||
.nest(2)
|
.nest(2)
|
||||||
.group()
|
.group()
|
||||||
}
|
}
|
||||||
|
@ -87,11 +169,7 @@ fn expr<'a>(c: &Ctx, p: EPrec, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a,
|
||||||
.append("]")
|
.append("]")
|
||||||
.group(),
|
.group(),
|
||||||
),
|
),
|
||||||
Var(sym, _) | AbilityMember(sym, _, _) => f.text(format!(
|
Var(sym, _) | AbilityMember(sym, _, _) => pp_sym(c, f, *sym),
|
||||||
"{}.{}",
|
|
||||||
sym.module_string(c.interns),
|
|
||||||
sym.as_str(c.interns),
|
|
||||||
)),
|
|
||||||
When {
|
When {
|
||||||
loc_cond, branches, ..
|
loc_cond, branches, ..
|
||||||
} => maybe_paren!(
|
} => maybe_paren!(
|
||||||
|
@ -184,6 +262,7 @@ fn expr<'a>(c: &Ctx, p: EPrec, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a,
|
||||||
Closure(ClosureData {
|
Closure(ClosureData {
|
||||||
arguments,
|
arguments,
|
||||||
loc_body,
|
loc_body,
|
||||||
|
name,
|
||||||
..
|
..
|
||||||
}) => f
|
}) => f
|
||||||
.text("\\")
|
.text("\\")
|
||||||
|
@ -195,7 +274,13 @@ fn expr<'a>(c: &Ctx, p: EPrec, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a,
|
||||||
f.text(", "),
|
f.text(", "),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.append(f.text(" ->"))
|
.append(if c.print_lambda_names {
|
||||||
|
f.text(" -[")
|
||||||
|
.append(pp_sym(c, f, *name))
|
||||||
|
.append(f.text("]->"))
|
||||||
|
} else {
|
||||||
|
f.text(" ->")
|
||||||
|
})
|
||||||
.append(f.line())
|
.append(f.line())
|
||||||
.append(expr(c, Free, f, &loc_body.value))
|
.append(expr(c, Free, f, &loc_body.value))
|
||||||
.nest(2)
|
.nest(2)
|
||||||
|
@ -290,6 +375,18 @@ fn expr<'a>(c: &Ctx, p: EPrec, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pp_sym<'a>(c: &Ctx, f: &'a Arena<'a>, sym: Symbol) -> DocBuilder<'a, Arena<'a>> {
|
||||||
|
if sym.module_id() == c.home {
|
||||||
|
f.text(sym.as_str(c.interns).to_owned())
|
||||||
|
} else {
|
||||||
|
f.text(format!(
|
||||||
|
"{}.{}",
|
||||||
|
sym.module_string(c.interns),
|
||||||
|
sym.as_str(c.interns),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn branch<'a>(c: &Ctx, f: &'a Arena<'a>, b: &'a WhenBranch) -> DocBuilder<'a, Arena<'a>> {
|
fn branch<'a>(c: &Ctx, f: &'a Arena<'a>, b: &'a WhenBranch) -> DocBuilder<'a, Arena<'a>> {
|
||||||
let WhenBranch {
|
let WhenBranch {
|
||||||
patterns,
|
patterns,
|
||||||
|
@ -333,11 +430,7 @@ fn pattern<'a>(
|
||||||
Identifier(sym)
|
Identifier(sym)
|
||||||
| AbilityMemberSpecialization {
|
| AbilityMemberSpecialization {
|
||||||
specializes: sym, ..
|
specializes: sym, ..
|
||||||
} => f.text(format!(
|
} => pp_sym(c, f, *sym),
|
||||||
"{}.{}",
|
|
||||||
sym.module_string(c.interns),
|
|
||||||
sym.as_str(c.interns),
|
|
||||||
)),
|
|
||||||
AppliedTag {
|
AppliedTag {
|
||||||
tag_name,
|
tag_name,
|
||||||
arguments,
|
arguments,
|
||||||
|
@ -373,12 +466,12 @@ fn pattern<'a>(
|
||||||
f.intersperse(
|
f.intersperse(
|
||||||
destructs.iter().map(|l| &l.value).map(
|
destructs.iter().map(|l| &l.value).map(
|
||||||
|RecordDestruct { label, typ, .. }| match typ {
|
|RecordDestruct { label, typ, .. }| match typ {
|
||||||
roc_can::pattern::DestructType::Required => f.text(label.as_str()),
|
crate::pattern::DestructType::Required => f.text(label.as_str()),
|
||||||
roc_can::pattern::DestructType::Optional(_, e) => f
|
crate::pattern::DestructType::Optional(_, e) => f
|
||||||
.text(label.as_str())
|
.text(label.as_str())
|
||||||
.append(f.text(" ? "))
|
.append(f.text(" ? "))
|
||||||
.append(expr(c, EPrec::Free, f, &e.value)),
|
.append(expr(c, EPrec::Free, f, &e.value)),
|
||||||
roc_can::pattern::DestructType::Guard(_, p) => f
|
crate::pattern::DestructType::Guard(_, p) => f
|
||||||
.text(label.as_str())
|
.text(label.as_str())
|
||||||
.append(f.text(": "))
|
.append(f.text(": "))
|
||||||
.append(pattern(c, Free, f, &p.value)),
|
.append(pattern(c, Free, f, &p.value)),
|
|
@ -28,3 +28,5 @@ pub mod string;
|
||||||
pub mod traverse;
|
pub mod traverse;
|
||||||
|
|
||||||
pub use derive::DERIVED_REGION;
|
pub use derive::DERIVED_REGION;
|
||||||
|
|
||||||
|
pub mod debug;
|
||||||
|
|
|
@ -705,7 +705,7 @@ pub fn constrain_expr(
|
||||||
expected,
|
expected,
|
||||||
);
|
);
|
||||||
|
|
||||||
constraints.exists_many([], [cond_con, continuation_con])
|
constraints.exists_many([*variable], [cond_con, continuation_con])
|
||||||
}
|
}
|
||||||
|
|
||||||
If {
|
If {
|
||||||
|
|
|
@ -709,7 +709,6 @@ fn float_with_precision<'a, 'ctx, 'env>(
|
||||||
match float_width {
|
match float_width {
|
||||||
FloatWidth::F64 => env.context.f64_type().const_float(value).into(),
|
FloatWidth::F64 => env.context.f64_type().const_float(value).into(),
|
||||||
FloatWidth::F32 => env.context.f32_type().const_float(value).into(),
|
FloatWidth::F32 => env.context.f32_type().const_float(value).into(),
|
||||||
FloatWidth::F128 => todo!("F128 is not implemented"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2586,7 +2585,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||||
condition: cond_symbol,
|
condition: cond_symbol,
|
||||||
region,
|
region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts: _,
|
variables,
|
||||||
remainder,
|
remainder,
|
||||||
} => {
|
} => {
|
||||||
let bd = env.builder;
|
let bd = env.builder;
|
||||||
|
@ -2621,6 +2620,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||||
*cond_symbol,
|
*cond_symbol,
|
||||||
*region,
|
*region,
|
||||||
lookups,
|
lookups,
|
||||||
|
variables,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let LlvmBackendMode::BinaryDev = env.mode {
|
if let LlvmBackendMode::BinaryDev = env.mode {
|
||||||
|
@ -2655,7 +2655,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||||
condition: cond_symbol,
|
condition: cond_symbol,
|
||||||
region,
|
region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts: _,
|
variables,
|
||||||
remainder,
|
remainder,
|
||||||
} => {
|
} => {
|
||||||
let bd = env.builder;
|
let bd = env.builder;
|
||||||
|
@ -2690,6 +2690,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||||
*cond_symbol,
|
*cond_symbol,
|
||||||
*region,
|
*region,
|
||||||
lookups,
|
lookups,
|
||||||
|
variables,
|
||||||
);
|
);
|
||||||
|
|
||||||
bd.build_unconditional_branch(then_block);
|
bd.build_unconditional_branch(then_block);
|
||||||
|
@ -3036,7 +3037,6 @@ fn build_switch_ir<'a, 'ctx, 'env>(
|
||||||
let int_type = match float_width {
|
let int_type = match float_width {
|
||||||
FloatWidth::F32 => env.context.i32_type(),
|
FloatWidth::F32 => env.context.i32_type(),
|
||||||
FloatWidth::F64 => env.context.i64_type(),
|
FloatWidth::F64 => env.context.i64_type(),
|
||||||
FloatWidth::F128 => env.context.i128_type(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
builder
|
builder
|
||||||
|
|
|
@ -111,7 +111,6 @@ fn build_eq_builtin<'a, 'ctx, 'env>(
|
||||||
use FloatWidth::*;
|
use FloatWidth::*;
|
||||||
|
|
||||||
let name = match float_width {
|
let name = match float_width {
|
||||||
F128 => "eq_f128",
|
|
||||||
F64 => "eq_f64",
|
F64 => "eq_f64",
|
||||||
F32 => "eq_f32",
|
F32 => "eq_f32",
|
||||||
};
|
};
|
||||||
|
@ -276,7 +275,6 @@ fn build_neq_builtin<'a, 'ctx, 'env>(
|
||||||
use FloatWidth::*;
|
use FloatWidth::*;
|
||||||
|
|
||||||
let name = match float_width {
|
let name = match float_width {
|
||||||
F128 => "neq_f128",
|
|
||||||
F64 => "neq_f64",
|
F64 => "neq_f64",
|
||||||
F32 => "neq_f32",
|
F32 => "neq_f32",
|
||||||
};
|
};
|
||||||
|
|
|
@ -202,7 +202,6 @@ pub fn float_type_from_float_width<'a, 'ctx, 'env>(
|
||||||
use FloatWidth::*;
|
use FloatWidth::*;
|
||||||
|
|
||||||
match float_width {
|
match float_width {
|
||||||
F128 => todo!("F128 is not implemented"),
|
|
||||||
F64 => env.context.f64_type(),
|
F64 => env.context.f64_type(),
|
||||||
F32 => env.context.f32_type(),
|
F32 => env.context.f32_type(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue};
|
||||||
use inkwell::AddressSpace;
|
use inkwell::AddressSpace;
|
||||||
use roc_builtins::bitcode;
|
use roc_builtins::bitcode;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
|
use roc_mono::ir::LookupType;
|
||||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||||
use roc_region::all::Region;
|
use roc_region::all::Region;
|
||||||
|
|
||||||
|
@ -143,6 +144,21 @@ pub(crate) fn notify_parent_dbg(env: &Env, shared_memory: &SharedMemoryPointer)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shape of expect frame:
|
||||||
|
//
|
||||||
|
// ===
|
||||||
|
// Fixed-size header
|
||||||
|
// ===
|
||||||
|
// /-- ptr_lookup_1 (ptr_size)
|
||||||
|
// | var_lookup_1 (u32)
|
||||||
|
// | ..
|
||||||
|
// | ptr_lookup_n (ptr_size)
|
||||||
|
// | var_lookup_n (u32)
|
||||||
|
// \-> lookup_val_1 (varsize)
|
||||||
|
// ..
|
||||||
|
// lookup_val_n (varsize)
|
||||||
|
//
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
scope: &Scope<'a, 'ctx>,
|
scope: &Scope<'a, 'ctx>,
|
||||||
|
@ -151,6 +167,7 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||||
condition: Symbol,
|
condition: Symbol,
|
||||||
region: Region,
|
region: Region,
|
||||||
lookups: &[Symbol],
|
lookups: &[Symbol],
|
||||||
|
lookup_variables: &[LookupType],
|
||||||
) {
|
) {
|
||||||
let original_ptr = shared_memory.0;
|
let original_ptr = shared_memory.0;
|
||||||
|
|
||||||
|
@ -160,9 +177,11 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let after_header = offset;
|
let after_header = offset;
|
||||||
|
|
||||||
let space_for_offsets = env
|
let space_for_offsets = env.ptr_int().const_int(
|
||||||
.ptr_int()
|
(lookups.len() * env.target_info.ptr_size() + lookups.len() * std::mem::size_of::<u32>())
|
||||||
.const_int((lookups.len() * env.target_info.ptr_size()) as _, false);
|
as _,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
let mut lookup_starts = bumpalo::collections::Vec::with_capacity_in(lookups.len(), env.arena);
|
let mut lookup_starts = bumpalo::collections::Vec::with_capacity_in(lookups.len(), env.arena);
|
||||||
|
|
||||||
|
@ -203,14 +222,43 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||||
{
|
{
|
||||||
let mut offset = after_header;
|
let mut offset = after_header;
|
||||||
|
|
||||||
for lookup_start in lookup_starts {
|
for (lookup_start, lookup_var) in lookup_starts.into_iter().zip(lookup_variables) {
|
||||||
|
// Store the pointer to the value
|
||||||
|
{
|
||||||
build_copy(env, original_ptr, offset, lookup_start.into());
|
build_copy(env, original_ptr, offset, lookup_start.into());
|
||||||
|
|
||||||
let ptr_width = env
|
let ptr_width = env
|
||||||
.ptr_int()
|
.ptr_int()
|
||||||
.const_int(env.target_info.ptr_size() as _, false);
|
.const_int(env.target_info.ptr_size() as _, false);
|
||||||
|
|
||||||
offset = env.builder.build_int_add(offset, ptr_width, "offset")
|
offset = env.builder.build_int_add(offset, ptr_width, "offset");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the specialized variable of the value
|
||||||
|
{
|
||||||
|
let ptr = unsafe {
|
||||||
|
env.builder
|
||||||
|
.build_in_bounds_gep(original_ptr, &[offset], "at_current_offset")
|
||||||
|
};
|
||||||
|
|
||||||
|
let u32_ptr = env.context.i32_type().ptr_type(AddressSpace::Generic);
|
||||||
|
let ptr = env
|
||||||
|
.builder
|
||||||
|
.build_pointer_cast(ptr, u32_ptr, "cast_ptr_type");
|
||||||
|
|
||||||
|
let var_value = env
|
||||||
|
.context
|
||||||
|
.i32_type()
|
||||||
|
.const_int(lookup_var.index() as _, false);
|
||||||
|
|
||||||
|
env.builder.build_store(ptr, var_value);
|
||||||
|
|
||||||
|
let var_size = env
|
||||||
|
.ptr_int()
|
||||||
|
.const_int(std::mem::size_of::<u32>() as _, false);
|
||||||
|
|
||||||
|
offset = env.builder.build_int_add(offset, var_size, "offset");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,6 @@ fn add_float_intrinsic<'ctx, F>(
|
||||||
|
|
||||||
check!(FloatWidth::F32, ctx.f32_type());
|
check!(FloatWidth::F32, ctx.f32_type());
|
||||||
check!(FloatWidth::F64, ctx.f64_type());
|
check!(FloatWidth::F64, ctx.f64_type());
|
||||||
// check!(IntWidth::F128, ctx.i128_type());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_int_intrinsic<'ctx, F>(
|
fn add_int_intrinsic<'ctx, F>(
|
||||||
|
|
|
@ -11,7 +11,7 @@ use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
|
||||||
use roc_error_macros::internal_error;
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::{low_level::LowLevel, symbol::Symbol};
|
use roc_module::{low_level::LowLevel, symbol::Symbol};
|
||||||
use roc_mono::{
|
use roc_mono::{
|
||||||
ir::HigherOrderLowLevel,
|
ir::{HigherOrderLowLevel, LookupType},
|
||||||
layout::{Builtin, LambdaSet, Layout, LayoutIds},
|
layout::{Builtin, LambdaSet, Layout, LayoutIds},
|
||||||
};
|
};
|
||||||
use roc_target::PtrWidth;
|
use roc_target::PtrWidth;
|
||||||
|
@ -1120,14 +1120,19 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Dbg => {
|
Dbg => {
|
||||||
// now what
|
assert_eq!(args.len(), 2);
|
||||||
arguments!(condition);
|
let condition = load_symbol(scope, &args[0]);
|
||||||
|
let dbg_spec_var_symbol = args[1];
|
||||||
|
|
||||||
if env.mode.runs_expects() {
|
if env.mode.runs_expects() {
|
||||||
let region = unsafe { std::mem::transmute::<_, roc_region::all::Region>(args[0]) };
|
let region = unsafe { std::mem::transmute::<_, roc_region::all::Region>(args[0]) };
|
||||||
|
|
||||||
let shared_memory = crate::llvm::expect::SharedMemoryPointer::get(env);
|
let shared_memory = crate::llvm::expect::SharedMemoryPointer::get(env);
|
||||||
|
|
||||||
|
// HACK(dbg-spec-var): the specialized type variable is passed along as a fake symbol
|
||||||
|
let specialized_var =
|
||||||
|
unsafe { LookupType::from_index(dbg_spec_var_symbol.ident_id().index() as _) };
|
||||||
|
|
||||||
crate::llvm::expect::clone_to_shared_memory(
|
crate::llvm::expect::clone_to_shared_memory(
|
||||||
env,
|
env,
|
||||||
scope,
|
scope,
|
||||||
|
@ -1136,6 +1141,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
args[0],
|
args[0],
|
||||||
region,
|
region,
|
||||||
&[args[0]],
|
&[args[0]],
|
||||||
|
&[specialized_var],
|
||||||
);
|
);
|
||||||
|
|
||||||
crate::llvm::expect::notify_parent_dbg(env, &shared_memory);
|
crate::llvm::expect::notify_parent_dbg(env, &shared_memory);
|
||||||
|
@ -2124,13 +2130,6 @@ fn build_float_unary_op<'a, 'ctx, 'env>(
|
||||||
"f64_to_f32",
|
"f64_to_f32",
|
||||||
),
|
),
|
||||||
(FloatWidth::F64, FloatWidth::F64) => arg.into(),
|
(FloatWidth::F64, FloatWidth::F64) => arg.into(),
|
||||||
(FloatWidth::F128, FloatWidth::F128) => arg.into(),
|
|
||||||
(FloatWidth::F128, _) => {
|
|
||||||
unimplemented!("I cannot handle F128 with Num.toFrac yet")
|
|
||||||
}
|
|
||||||
(_, FloatWidth::F128) => {
|
|
||||||
unimplemented!("I cannot handle F128 with Num.toFrac yet")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NumCeiling => {
|
NumCeiling => {
|
||||||
|
|
|
@ -21,7 +21,6 @@ pub enum StackMemoryFormat {
|
||||||
/// Record, Str, List, etc.
|
/// Record, Str, List, etc.
|
||||||
DataStructure,
|
DataStructure,
|
||||||
Int128,
|
Int128,
|
||||||
Float128,
|
|
||||||
Decimal,
|
Decimal,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,11 +70,6 @@ impl WasmLayout {
|
||||||
match float_width {
|
match float_width {
|
||||||
F32 => Self::Primitive(ValueType::F32, size),
|
F32 => Self::Primitive(ValueType::F32, size),
|
||||||
F64 => Self::Primitive(ValueType::F64, size),
|
F64 => Self::Primitive(ValueType::F64, size),
|
||||||
F128 => Self::StackMemory {
|
|
||||||
size,
|
|
||||||
alignment_bytes,
|
|
||||||
format: StackMemoryFormat::Float128,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +150,7 @@ impl CallConv {
|
||||||
use ValueType::*;
|
use ValueType::*;
|
||||||
|
|
||||||
match format {
|
match format {
|
||||||
Int128 | Float128 | Decimal => &[I64, I64],
|
Int128 | Decimal => &[I64, I64],
|
||||||
|
|
||||||
DataStructure => {
|
DataStructure => {
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
|
@ -191,7 +185,7 @@ impl CallConv {
|
||||||
use StackMemoryFormat::*;
|
use StackMemoryFormat::*;
|
||||||
|
|
||||||
match format {
|
match format {
|
||||||
Int128 | Float128 | Decimal => WriteToPointerArg,
|
Int128 | Decimal => WriteToPointerArg,
|
||||||
|
|
||||||
DataStructure => {
|
DataStructure => {
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
|
|
|
@ -30,7 +30,6 @@ enum CodeGenNumType {
|
||||||
F32, // Supported in Wasm instruction set
|
F32, // Supported in Wasm instruction set
|
||||||
F64, // Supported in Wasm instruction set
|
F64, // Supported in Wasm instruction set
|
||||||
I128, // Bytes in memory, needs Zig builtins
|
I128, // Bytes in memory, needs Zig builtins
|
||||||
F128, // Bytes in memory, needs Zig builtins
|
|
||||||
Decimal, // Bytes in memory, needs Zig builtins
|
Decimal, // Bytes in memory, needs Zig builtins
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +65,6 @@ impl From<Layout<'_>> for CodeGenNumType {
|
||||||
Builtin::Float(float_width) => match float_width {
|
Builtin::Float(float_width) => match float_width {
|
||||||
FloatWidth::F32 => F32,
|
FloatWidth::F32 => F32,
|
||||||
FloatWidth::F64 => F64,
|
FloatWidth::F64 => F64,
|
||||||
FloatWidth::F128 => F128,
|
|
||||||
},
|
},
|
||||||
Builtin::Decimal => Decimal,
|
Builtin::Decimal => Decimal,
|
||||||
_ => not_num_error(),
|
_ => not_num_error(),
|
||||||
|
@ -91,7 +89,6 @@ impl From<StackMemoryFormat> for CodeGenNumType {
|
||||||
fn from(format: StackMemoryFormat) -> CodeGenNumType {
|
fn from(format: StackMemoryFormat) -> CodeGenNumType {
|
||||||
match format {
|
match format {
|
||||||
StackMemoryFormat::Int128 => CodeGenNumType::I128,
|
StackMemoryFormat::Int128 => CodeGenNumType::I128,
|
||||||
StackMemoryFormat::Float128 => CodeGenNumType::F128,
|
|
||||||
StackMemoryFormat::Decimal => CodeGenNumType::Decimal,
|
StackMemoryFormat::Decimal => CodeGenNumType::Decimal,
|
||||||
StackMemoryFormat::DataStructure => {
|
StackMemoryFormat::DataStructure => {
|
||||||
internal_error!("Tried to perform a Num low-level operation on a data structure")
|
internal_error!("Tried to perform a Num low-level operation on a data structure")
|
||||||
|
@ -804,7 +801,6 @@ impl<'a> LowLevelCall<'a> {
|
||||||
self.load_args(backend);
|
self.load_args(backend);
|
||||||
backend.code_builder.f64_add()
|
backend.code_builder.f64_add()
|
||||||
}
|
}
|
||||||
FloatWidth::F128 => todo!("Num.add for f128"),
|
|
||||||
},
|
},
|
||||||
Layout::Builtin(Builtin::Decimal) => {
|
Layout::Builtin(Builtin::Decimal) => {
|
||||||
self.load_args_and_call_zig(backend, bitcode::DEC_ADD_OR_PANIC)
|
self.load_args_and_call_zig(backend, bitcode::DEC_ADD_OR_PANIC)
|
||||||
|
@ -841,7 +837,6 @@ impl<'a> LowLevelCall<'a> {
|
||||||
self.load_args(backend);
|
self.load_args(backend);
|
||||||
backend.code_builder.f64_add()
|
backend.code_builder.f64_add()
|
||||||
}
|
}
|
||||||
FloatWidth::F128 => todo!("Num.add for f128"),
|
|
||||||
},
|
},
|
||||||
Layout::Builtin(Builtin::Decimal) => {
|
Layout::Builtin(Builtin::Decimal) => {
|
||||||
// TODO: don't panic
|
// TODO: don't panic
|
||||||
|
@ -897,7 +892,6 @@ impl<'a> LowLevelCall<'a> {
|
||||||
self.load_args(backend);
|
self.load_args(backend);
|
||||||
backend.code_builder.f64_sub()
|
backend.code_builder.f64_sub()
|
||||||
}
|
}
|
||||||
FloatWidth::F128 => todo!("Num.sub for f128"),
|
|
||||||
},
|
},
|
||||||
Layout::Builtin(Builtin::Decimal) => {
|
Layout::Builtin(Builtin::Decimal) => {
|
||||||
self.load_args_and_call_zig(backend, bitcode::DEC_SUB_OR_PANIC)
|
self.load_args_and_call_zig(backend, bitcode::DEC_SUB_OR_PANIC)
|
||||||
|
@ -934,7 +928,6 @@ impl<'a> LowLevelCall<'a> {
|
||||||
self.load_args(backend);
|
self.load_args(backend);
|
||||||
backend.code_builder.f64_sub()
|
backend.code_builder.f64_sub()
|
||||||
}
|
}
|
||||||
FloatWidth::F128 => todo!("Num.sub for f128"),
|
|
||||||
},
|
},
|
||||||
Layout::Builtin(Builtin::Decimal) => {
|
Layout::Builtin(Builtin::Decimal) => {
|
||||||
// TODO: don't panic
|
// TODO: don't panic
|
||||||
|
@ -988,7 +981,6 @@ impl<'a> LowLevelCall<'a> {
|
||||||
self.load_args(backend);
|
self.load_args(backend);
|
||||||
backend.code_builder.f64_mul()
|
backend.code_builder.f64_mul()
|
||||||
}
|
}
|
||||||
FloatWidth::F128 => todo!("Num.mul for f128"),
|
|
||||||
},
|
},
|
||||||
Layout::Builtin(Builtin::Decimal) => {
|
Layout::Builtin(Builtin::Decimal) => {
|
||||||
self.load_args_and_call_zig(backend, bitcode::DEC_MUL_OR_PANIC)
|
self.load_args_and_call_zig(backend, bitcode::DEC_MUL_OR_PANIC)
|
||||||
|
@ -1024,7 +1016,6 @@ impl<'a> LowLevelCall<'a> {
|
||||||
self.load_args(backend);
|
self.load_args(backend);
|
||||||
backend.code_builder.f64_mul()
|
backend.code_builder.f64_mul()
|
||||||
}
|
}
|
||||||
FloatWidth::F128 => todo!("Num.mul for f128"),
|
|
||||||
},
|
},
|
||||||
Layout::Builtin(Builtin::Decimal) => {
|
Layout::Builtin(Builtin::Decimal) => {
|
||||||
// TODO: don't panic
|
// TODO: don't panic
|
||||||
|
@ -1466,9 +1457,6 @@ impl<'a> LowLevelCall<'a> {
|
||||||
Layout::Builtin(Builtin::Float(FloatWidth::F64)) => {
|
Layout::Builtin(Builtin::Float(FloatWidth::F64)) => {
|
||||||
backend.code_builder.f64_sqrt()
|
backend.code_builder.f64_sqrt()
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::Float(FloatWidth::F128)) => {
|
|
||||||
todo!("sqrt for f128")
|
|
||||||
}
|
|
||||||
_ => panic_ret_type(),
|
_ => panic_ret_type(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2004,8 +1992,6 @@ impl<'a> LowLevelCall<'a> {
|
||||||
|
|
||||||
StackMemoryFormat::Int128 => Self::eq_num128_bytes(backend, locations),
|
StackMemoryFormat::Int128 => Self::eq_num128_bytes(backend, locations),
|
||||||
|
|
||||||
StackMemoryFormat::Float128 => todo!("equality for f128"),
|
|
||||||
|
|
||||||
StackMemoryFormat::DataStructure => {
|
StackMemoryFormat::DataStructure => {
|
||||||
internal_error!("Data structure equality is handled elsewhere")
|
internal_error!("Data structure equality is handled elsewhere")
|
||||||
}
|
}
|
||||||
|
@ -2052,7 +2038,6 @@ impl<'a> LowLevelCall<'a> {
|
||||||
FloatWidth::F64 => {
|
FloatWidth::F64 => {
|
||||||
self.load_args_and_call_zig(backend, &bitcode::STR_FROM_FLOAT[width]);
|
self.load_args_and_call_zig(backend, &bitcode::STR_FROM_FLOAT[width]);
|
||||||
}
|
}
|
||||||
FloatWidth::F128 => todo!("F128 to Str"),
|
|
||||||
},
|
},
|
||||||
Layout::Builtin(Builtin::Decimal) => {
|
Layout::Builtin(Builtin::Decimal) => {
|
||||||
self.load_args_and_call_zig(backend, bitcode::DEC_TO_STR)
|
self.load_args_and_call_zig(backend, bitcode::DEC_TO_STR)
|
||||||
|
@ -2090,27 +2075,13 @@ fn num_is_finite(backend: &mut WasmBackend<'_>, argument: Symbol) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StackMemory {
|
StackMemory { format, .. } => {
|
||||||
format, location, ..
|
|
||||||
} => {
|
|
||||||
let (local_id, offset) = location.local_and_offset(backend.storage.stack_frame_pointer);
|
|
||||||
|
|
||||||
match format {
|
match format {
|
||||||
// Integers and fixed-point numbers are always finite. Just return True.
|
// Integers and fixed-point numbers are always finite. Just return True.
|
||||||
StackMemoryFormat::Int128 | StackMemoryFormat::Decimal => {
|
StackMemoryFormat::Int128 | StackMemoryFormat::Decimal => {
|
||||||
backend.code_builder.i32_const(1)
|
backend.code_builder.i32_const(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// f128 is not supported anywhere else but it's easy to support it here, so why not...
|
|
||||||
StackMemoryFormat::Float128 => {
|
|
||||||
backend.code_builder.get_local(local_id);
|
|
||||||
backend.code_builder.i64_load(Align::Bytes4, offset + 8);
|
|
||||||
backend.code_builder.i64_const(0x7fff_0000_0000_0000);
|
|
||||||
backend.code_builder.i64_and();
|
|
||||||
backend.code_builder.i64_const(0x7fff_0000_0000_0000);
|
|
||||||
backend.code_builder.i64_ne();
|
|
||||||
}
|
|
||||||
|
|
||||||
StackMemoryFormat::DataStructure => {
|
StackMemoryFormat::DataStructure => {
|
||||||
internal_error!("Tried to perform NumIsFinite on a data structure")
|
internal_error!("Tried to perform NumIsFinite on a data structure")
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,7 +252,7 @@ impl<'a> Storage<'a> {
|
||||||
.extend_from_slice(CallConv::C.stack_memory_arg_types(size, format));
|
.extend_from_slice(CallConv::C.stack_memory_arg_types(size, format));
|
||||||
|
|
||||||
let location = match format {
|
let location = match format {
|
||||||
Int128 | Float128 | Decimal => {
|
Int128 | Decimal => {
|
||||||
// passed as two i64's but stored in the stack frame
|
// passed as two i64's but stored in the stack frame
|
||||||
wide_number_args.push(local_index);
|
wide_number_args.push(local_index);
|
||||||
let loc =
|
let loc =
|
||||||
|
|
|
@ -140,7 +140,6 @@ struct ModuleCache<'a> {
|
||||||
found_specializations: MutMap<ModuleId, FoundSpecializationsModule<'a>>,
|
found_specializations: MutMap<ModuleId, FoundSpecializationsModule<'a>>,
|
||||||
late_specializations: MutMap<ModuleId, LateSpecializationsModule<'a>>,
|
late_specializations: MutMap<ModuleId, LateSpecializationsModule<'a>>,
|
||||||
external_specializations_requested: MutMap<ModuleId, Vec<ExternalSpecializations<'a>>>,
|
external_specializations_requested: MutMap<ModuleId, Vec<ExternalSpecializations<'a>>>,
|
||||||
expectations: VecMap<ModuleId, Expectations>,
|
|
||||||
|
|
||||||
/// Various information
|
/// Various information
|
||||||
imports: MutMap<ModuleId, MutSet<ModuleId>>,
|
imports: MutMap<ModuleId, MutSet<ModuleId>>,
|
||||||
|
@ -217,7 +216,6 @@ impl Default for ModuleCache<'_> {
|
||||||
can_problems: Default::default(),
|
can_problems: Default::default(),
|
||||||
type_problems: Default::default(),
|
type_problems: Default::default(),
|
||||||
sources: Default::default(),
|
sources: Default::default(),
|
||||||
expectations: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -437,6 +435,7 @@ fn start_phase<'a>(
|
||||||
decls,
|
decls,
|
||||||
ident_ids,
|
ident_ids,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
|
expectations,
|
||||||
} = typechecked;
|
} = typechecked;
|
||||||
|
|
||||||
let mut imported_module_thunks = bumpalo::collections::Vec::new_in(arena);
|
let mut imported_module_thunks = bumpalo::collections::Vec::new_in(arena);
|
||||||
|
@ -453,8 +452,8 @@ fn start_phase<'a>(
|
||||||
|
|
||||||
let derived_module = SharedDerivedModule::clone(&state.derived_module);
|
let derived_module = SharedDerivedModule::clone(&state.derived_module);
|
||||||
|
|
||||||
let build_expects = matches!(state.exec_mode, ExecutionMode::Test)
|
let build_expects =
|
||||||
&& state.module_cache.expectations.contains_key(&module_id);
|
matches!(state.exec_mode, ExecutionMode::Test) && expectations.is_some();
|
||||||
|
|
||||||
BuildTask::BuildPendingSpecializations {
|
BuildTask::BuildPendingSpecializations {
|
||||||
layout_cache,
|
layout_cache,
|
||||||
|
@ -469,6 +468,7 @@ fn start_phase<'a>(
|
||||||
// TODO: awful, how can we get rid of the clone?
|
// TODO: awful, how can we get rid of the clone?
|
||||||
exposed_by_module: state.exposed_types.clone(),
|
exposed_by_module: state.exposed_types.clone(),
|
||||||
derived_module,
|
derived_module,
|
||||||
|
expectations,
|
||||||
build_expects,
|
build_expects,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -490,8 +490,14 @@ fn start_phase<'a>(
|
||||||
specializations_we_must_make.extend(derived_synth_specializations)
|
specializations_we_must_make.extend(derived_synth_specializations)
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut ident_ids, mut subs, mut procs_base, layout_cache, mut module_timing) =
|
let (
|
||||||
if state.make_specializations_pass.current_pass() == 1
|
mut ident_ids,
|
||||||
|
mut subs,
|
||||||
|
expectations,
|
||||||
|
mut procs_base,
|
||||||
|
layout_cache,
|
||||||
|
mut module_timing,
|
||||||
|
) = if state.make_specializations_pass.current_pass() == 1
|
||||||
&& module_id == ModuleId::DERIVED_GEN
|
&& module_id == ModuleId::DERIVED_GEN
|
||||||
{
|
{
|
||||||
// This is the first time the derived module is introduced into the load
|
// This is the first time the derived module is introduced into the load
|
||||||
|
@ -500,6 +506,7 @@ fn start_phase<'a>(
|
||||||
(
|
(
|
||||||
IdentIds::default(),
|
IdentIds::default(),
|
||||||
Subs::default(),
|
Subs::default(),
|
||||||
|
None, // no expectations for derived module
|
||||||
ProcsBase::default(),
|
ProcsBase::default(),
|
||||||
LayoutCache::new(state.layout_interner.fork(), state.target_info),
|
LayoutCache::new(state.layout_interner.fork(), state.target_info),
|
||||||
ModuleTiming::new(Instant::now()),
|
ModuleTiming::new(Instant::now()),
|
||||||
|
@ -518,6 +525,7 @@ fn start_phase<'a>(
|
||||||
layout_cache,
|
layout_cache,
|
||||||
module_timing,
|
module_timing,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
|
expectations,
|
||||||
} = found_specializations;
|
} = found_specializations;
|
||||||
|
|
||||||
let our_exposed_types = state
|
let our_exposed_types = state
|
||||||
|
@ -535,11 +543,19 @@ fn start_phase<'a>(
|
||||||
our_exposed_types.exposed_types_storage_subs,
|
our_exposed_types.exposed_types_storage_subs,
|
||||||
);
|
);
|
||||||
|
|
||||||
(ident_ids, subs, procs_base, layout_cache, module_timing)
|
(
|
||||||
|
ident_ids,
|
||||||
|
subs,
|
||||||
|
expectations,
|
||||||
|
procs_base,
|
||||||
|
layout_cache,
|
||||||
|
module_timing,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
let LateSpecializationsModule {
|
let LateSpecializationsModule {
|
||||||
ident_ids,
|
ident_ids,
|
||||||
subs,
|
subs,
|
||||||
|
expectations,
|
||||||
module_timing,
|
module_timing,
|
||||||
layout_cache,
|
layout_cache,
|
||||||
procs_base,
|
procs_base,
|
||||||
|
@ -549,7 +565,14 @@ fn start_phase<'a>(
|
||||||
.remove(&module_id)
|
.remove(&module_id)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
(ident_ids, subs, procs_base, layout_cache, module_timing)
|
(
|
||||||
|
ident_ids,
|
||||||
|
subs,
|
||||||
|
expectations,
|
||||||
|
procs_base,
|
||||||
|
layout_cache,
|
||||||
|
module_timing,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
if module_id == ModuleId::DERIVED_GEN {
|
if module_id == ModuleId::DERIVED_GEN {
|
||||||
|
@ -581,6 +604,7 @@ fn start_phase<'a>(
|
||||||
// TODO: awful, how can we get rid of the clone?
|
// TODO: awful, how can we get rid of the clone?
|
||||||
exposed_by_module: state.exposed_types.clone(),
|
exposed_by_module: state.exposed_types.clone(),
|
||||||
derived_module,
|
derived_module,
|
||||||
|
expectations,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -681,6 +705,7 @@ pub struct TypeCheckedModule<'a> {
|
||||||
pub decls: Declarations,
|
pub decls: Declarations,
|
||||||
pub ident_ids: IdentIds,
|
pub ident_ids: IdentIds,
|
||||||
pub abilities_store: AbilitiesStore,
|
pub abilities_store: AbilitiesStore,
|
||||||
|
pub expectations: Option<Expectations>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -691,6 +716,7 @@ struct FoundSpecializationsModule<'a> {
|
||||||
subs: Subs,
|
subs: Subs,
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
abilities_store: AbilitiesStore,
|
abilities_store: AbilitiesStore,
|
||||||
|
expectations: Option<Expectations>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -700,6 +726,7 @@ struct LateSpecializationsModule<'a> {
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
layout_cache: LayoutCache<'a>,
|
layout_cache: LayoutCache<'a>,
|
||||||
procs_base: ProcsBase<'a>,
|
procs_base: ProcsBase<'a>,
|
||||||
|
expectations: Option<Expectations>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -833,6 +860,7 @@ enum Msg<'a> {
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
abilities_store: AbilitiesStore,
|
abilities_store: AbilitiesStore,
|
||||||
toplevel_expects: ToplevelExpects,
|
toplevel_expects: ToplevelExpects,
|
||||||
|
expectations: Option<Expectations>,
|
||||||
},
|
},
|
||||||
MadeSpecializations {
|
MadeSpecializations {
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
|
@ -844,6 +872,7 @@ enum Msg<'a> {
|
||||||
update_mode_ids: UpdateModeIds,
|
update_mode_ids: UpdateModeIds,
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
subs: Subs,
|
subs: Subs,
|
||||||
|
expectations: Option<Expectations>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// The task is to only typecheck AND monomorphize modules
|
/// The task is to only typecheck AND monomorphize modules
|
||||||
|
@ -854,6 +883,7 @@ enum Msg<'a> {
|
||||||
/// DO NOT use the one on state; that is left in an empty state after specialization is complete!
|
/// DO NOT use the one on state; that is left in an empty state after specialization is complete!
|
||||||
layout_interner: STLayoutInterner<'a>,
|
layout_interner: STLayoutInterner<'a>,
|
||||||
exposed_to_host: ExposedToHost,
|
exposed_to_host: ExposedToHost,
|
||||||
|
module_expectations: VecMap<ModuleId, Expectations>,
|
||||||
},
|
},
|
||||||
|
|
||||||
FailedToParse(FileError<'a, SyntaxError<'a>>),
|
FailedToParse(FileError<'a, SyntaxError<'a>>),
|
||||||
|
@ -1150,6 +1180,7 @@ enum BuildTask<'a> {
|
||||||
exposed_by_module: ExposedByModule,
|
exposed_by_module: ExposedByModule,
|
||||||
abilities_store: AbilitiesStore,
|
abilities_store: AbilitiesStore,
|
||||||
derived_module: SharedDerivedModule,
|
derived_module: SharedDerivedModule,
|
||||||
|
expectations: Option<Expectations>,
|
||||||
build_expects: bool,
|
build_expects: bool,
|
||||||
},
|
},
|
||||||
MakeSpecializations {
|
MakeSpecializations {
|
||||||
|
@ -1163,6 +1194,7 @@ enum BuildTask<'a> {
|
||||||
exposed_by_module: ExposedByModule,
|
exposed_by_module: ExposedByModule,
|
||||||
world_abilities: WorldAbilities,
|
world_abilities: WorldAbilities,
|
||||||
derived_module: SharedDerivedModule,
|
derived_module: SharedDerivedModule,
|
||||||
|
expectations: Option<Expectations>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1671,6 +1703,7 @@ fn state_thread_step<'a>(
|
||||||
subs,
|
subs,
|
||||||
layout_interner,
|
layout_interner,
|
||||||
exposed_to_host,
|
exposed_to_host,
|
||||||
|
module_expectations,
|
||||||
} => {
|
} => {
|
||||||
// We're done! There should be no more messages pending.
|
// We're done! There should be no more messages pending.
|
||||||
debug_assert!(msg_rx.is_empty());
|
debug_assert!(msg_rx.is_empty());
|
||||||
|
@ -1681,6 +1714,7 @@ fn state_thread_step<'a>(
|
||||||
subs,
|
subs,
|
||||||
layout_interner,
|
layout_interner,
|
||||||
exposed_to_host,
|
exposed_to_host,
|
||||||
|
module_expectations,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(ControlFlow::Break(LoadResult::Monomorphized(monomorphized)))
|
Ok(ControlFlow::Break(LoadResult::Monomorphized(monomorphized)))
|
||||||
|
@ -2636,23 +2670,20 @@ fn update<'a>(
|
||||||
.expect("root or this module is not yet known - that's a bug!")
|
.expect("root or this module is not yet known - that's a bug!")
|
||||||
};
|
};
|
||||||
|
|
||||||
if should_include_expects {
|
let opt_expectations = if should_include_expects {
|
||||||
let (path, _) = state.module_cache.sources.get(&module_id).unwrap();
|
let (path, _) = state.module_cache.sources.get(&module_id).unwrap();
|
||||||
|
|
||||||
let expectations = Expectations {
|
Some(Expectations {
|
||||||
expectations: loc_expects,
|
expectations: loc_expects,
|
||||||
dbgs: loc_dbgs,
|
dbgs: loc_dbgs,
|
||||||
subs: solved_subs.clone().into_inner(),
|
subs: solved_subs.clone().into_inner(),
|
||||||
path: path.to_owned(),
|
path: path.to_owned(),
|
||||||
ident_ids: ident_ids.clone(),
|
ident_ids: ident_ids.clone(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
state
|
|
||||||
.module_cache
|
|
||||||
.expectations
|
|
||||||
.insert(module_id, expectations);
|
|
||||||
}
|
|
||||||
|
|
||||||
let work = state.dependencies.notify(module_id, Phase::SolveTypes);
|
let work = state.dependencies.notify(module_id, Phase::SolveTypes);
|
||||||
|
|
||||||
// if there is a platform, the `platform` module provides host-exposed,
|
// if there is a platform, the `platform` module provides host-exposed,
|
||||||
|
@ -2764,6 +2795,7 @@ fn update<'a>(
|
||||||
decls,
|
decls,
|
||||||
ident_ids,
|
ident_ids,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
|
expectations: opt_expectations,
|
||||||
};
|
};
|
||||||
|
|
||||||
state
|
state
|
||||||
|
@ -2803,6 +2835,7 @@ fn update<'a>(
|
||||||
module_timing,
|
module_timing,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
toplevel_expects,
|
toplevel_expects,
|
||||||
|
expectations,
|
||||||
} => {
|
} => {
|
||||||
log!("found specializations for {:?}", module_id);
|
log!("found specializations for {:?}", module_id);
|
||||||
|
|
||||||
|
@ -2825,6 +2858,7 @@ fn update<'a>(
|
||||||
subs,
|
subs,
|
||||||
module_timing,
|
module_timing,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
|
expectations,
|
||||||
};
|
};
|
||||||
|
|
||||||
state
|
state
|
||||||
|
@ -2850,6 +2884,7 @@ fn update<'a>(
|
||||||
external_specializations_requested,
|
external_specializations_requested,
|
||||||
module_timing,
|
module_timing,
|
||||||
layout_cache,
|
layout_cache,
|
||||||
|
expectations,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
|
@ -2871,6 +2906,7 @@ fn update<'a>(
|
||||||
subs,
|
subs,
|
||||||
layout_cache,
|
layout_cache,
|
||||||
procs_base,
|
procs_base,
|
||||||
|
expectations,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2928,6 +2964,9 @@ fn update<'a>(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut module_expectations =
|
||||||
|
VecMap::with_capacity(state.module_cache.module_names.len());
|
||||||
|
|
||||||
// Flush late-specialization module information to the top-level of the state
|
// Flush late-specialization module information to the top-level of the state
|
||||||
// where it will be visible to others, since we don't need late specialization
|
// where it will be visible to others, since we don't need late specialization
|
||||||
// anymore.
|
// anymore.
|
||||||
|
@ -2939,6 +2978,7 @@ fn update<'a>(
|
||||||
module_timing,
|
module_timing,
|
||||||
layout_cache: _layout_cache,
|
layout_cache: _layout_cache,
|
||||||
procs_base: _,
|
procs_base: _,
|
||||||
|
expectations,
|
||||||
},
|
},
|
||||||
) in state.module_cache.late_specializations.drain()
|
) in state.module_cache.late_specializations.drain()
|
||||||
{
|
{
|
||||||
|
@ -2947,6 +2987,9 @@ fn update<'a>(
|
||||||
state.root_subs = Some(subs);
|
state.root_subs = Some(subs);
|
||||||
}
|
}
|
||||||
state.timings.insert(module_id, module_timing);
|
state.timings.insert(module_id, module_timing);
|
||||||
|
if let Some(expectations) = expectations {
|
||||||
|
module_expectations.insert(module_id, expectations);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
|
@ -3009,6 +3052,7 @@ fn update<'a>(
|
||||||
subs,
|
subs,
|
||||||
layout_interner,
|
layout_interner,
|
||||||
exposed_to_host: state.exposed_to_host.clone(),
|
exposed_to_host: state.exposed_to_host.clone(),
|
||||||
|
module_expectations,
|
||||||
})
|
})
|
||||||
.map_err(|_| LoadingProblem::MsgChannelDied)?;
|
.map_err(|_| LoadingProblem::MsgChannelDied)?;
|
||||||
|
|
||||||
|
@ -3146,6 +3190,7 @@ fn finish_specialization<'a>(
|
||||||
subs: Subs,
|
subs: Subs,
|
||||||
layout_interner: STLayoutInterner<'a>,
|
layout_interner: STLayoutInterner<'a>,
|
||||||
exposed_to_host: ExposedToHost,
|
exposed_to_host: ExposedToHost,
|
||||||
|
module_expectations: VecMap<ModuleId, Expectations>,
|
||||||
) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>> {
|
) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>> {
|
||||||
if false {
|
if false {
|
||||||
println!(
|
println!(
|
||||||
|
@ -3186,7 +3231,6 @@ fn finish_specialization<'a>(
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
let ModuleCache {
|
let ModuleCache {
|
||||||
expectations,
|
|
||||||
type_problems,
|
type_problems,
|
||||||
can_problems,
|
can_problems,
|
||||||
sources,
|
sources,
|
||||||
|
@ -3277,7 +3321,7 @@ fn finish_specialization<'a>(
|
||||||
can_problems,
|
can_problems,
|
||||||
type_problems,
|
type_problems,
|
||||||
output_path,
|
output_path,
|
||||||
expectations,
|
expectations: module_expectations,
|
||||||
exposed_to_host,
|
exposed_to_host,
|
||||||
module_id: state.root_id,
|
module_id: state.root_id,
|
||||||
subs,
|
subs,
|
||||||
|
@ -5395,6 +5439,7 @@ fn make_specializations<'a>(
|
||||||
world_abilities: WorldAbilities,
|
world_abilities: WorldAbilities,
|
||||||
exposed_by_module: &ExposedByModule,
|
exposed_by_module: &ExposedByModule,
|
||||||
derived_module: SharedDerivedModule,
|
derived_module: SharedDerivedModule,
|
||||||
|
mut expectations: Option<Expectations>,
|
||||||
) -> Msg<'a> {
|
) -> Msg<'a> {
|
||||||
let make_specializations_start = Instant::now();
|
let make_specializations_start = Instant::now();
|
||||||
let mut update_mode_ids = UpdateModeIds::new();
|
let mut update_mode_ids = UpdateModeIds::new();
|
||||||
|
@ -5402,6 +5447,7 @@ fn make_specializations<'a>(
|
||||||
let mut mono_env = roc_mono::ir::Env {
|
let mut mono_env = roc_mono::ir::Env {
|
||||||
arena,
|
arena,
|
||||||
subs: &mut subs,
|
subs: &mut subs,
|
||||||
|
expectation_subs: expectations.as_mut().map(|e| &mut e.subs),
|
||||||
home,
|
home,
|
||||||
ident_ids: &mut ident_ids,
|
ident_ids: &mut ident_ids,
|
||||||
target_info,
|
target_info,
|
||||||
|
@ -5453,6 +5499,7 @@ fn make_specializations<'a>(
|
||||||
procedures,
|
procedures,
|
||||||
update_mode_ids,
|
update_mode_ids,
|
||||||
subs,
|
subs,
|
||||||
|
expectations,
|
||||||
external_specializations_requested,
|
external_specializations_requested,
|
||||||
module_timing,
|
module_timing,
|
||||||
}
|
}
|
||||||
|
@ -5472,6 +5519,7 @@ fn build_pending_specializations<'a>(
|
||||||
exposed_by_module: &ExposedByModule,
|
exposed_by_module: &ExposedByModule,
|
||||||
abilities_store: AbilitiesStore,
|
abilities_store: AbilitiesStore,
|
||||||
derived_module: SharedDerivedModule,
|
derived_module: SharedDerivedModule,
|
||||||
|
mut expectations: Option<Expectations>,
|
||||||
build_expects: bool,
|
build_expects: bool,
|
||||||
) -> Msg<'a> {
|
) -> Msg<'a> {
|
||||||
let find_specializations_start = Instant::now();
|
let find_specializations_start = Instant::now();
|
||||||
|
@ -5492,6 +5540,7 @@ fn build_pending_specializations<'a>(
|
||||||
let mut mono_env = roc_mono::ir::Env {
|
let mut mono_env = roc_mono::ir::Env {
|
||||||
arena,
|
arena,
|
||||||
subs: &mut subs,
|
subs: &mut subs,
|
||||||
|
expectation_subs: expectations.as_mut().map(|e| &mut e.subs),
|
||||||
home,
|
home,
|
||||||
ident_ids: &mut ident_ids,
|
ident_ids: &mut ident_ids,
|
||||||
target_info,
|
target_info,
|
||||||
|
@ -5881,6 +5930,7 @@ fn build_pending_specializations<'a>(
|
||||||
module_timing,
|
module_timing,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
toplevel_expects,
|
toplevel_expects,
|
||||||
|
expectations,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5922,6 +5972,8 @@ fn load_derived_partial_procs<'a>(
|
||||||
let mut mono_env = roc_mono::ir::Env {
|
let mut mono_env = roc_mono::ir::Env {
|
||||||
arena,
|
arena,
|
||||||
subs,
|
subs,
|
||||||
|
// There are no derived expectations.
|
||||||
|
expectation_subs: None,
|
||||||
home,
|
home,
|
||||||
ident_ids,
|
ident_ids,
|
||||||
target_info,
|
target_info,
|
||||||
|
@ -6081,6 +6133,7 @@ fn run_task<'a>(
|
||||||
abilities_store,
|
abilities_store,
|
||||||
exposed_by_module,
|
exposed_by_module,
|
||||||
derived_module,
|
derived_module,
|
||||||
|
expectations,
|
||||||
build_expects,
|
build_expects,
|
||||||
} => Ok(build_pending_specializations(
|
} => Ok(build_pending_specializations(
|
||||||
arena,
|
arena,
|
||||||
|
@ -6096,6 +6149,7 @@ fn run_task<'a>(
|
||||||
&exposed_by_module,
|
&exposed_by_module,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
derived_module,
|
derived_module,
|
||||||
|
expectations,
|
||||||
build_expects,
|
build_expects,
|
||||||
)),
|
)),
|
||||||
MakeSpecializations {
|
MakeSpecializations {
|
||||||
|
@ -6109,6 +6163,7 @@ fn run_task<'a>(
|
||||||
world_abilities,
|
world_abilities,
|
||||||
exposed_by_module,
|
exposed_by_module,
|
||||||
derived_module,
|
derived_module,
|
||||||
|
expectations,
|
||||||
} => Ok(make_specializations(
|
} => Ok(make_specializations(
|
||||||
arena,
|
arena,
|
||||||
module_id,
|
module_id,
|
||||||
|
@ -6122,6 +6177,7 @@ fn run_task<'a>(
|
||||||
world_abilities,
|
world_abilities,
|
||||||
&exposed_by_module,
|
&exposed_by_module,
|
||||||
derived_module,
|
derived_module,
|
||||||
|
expectations,
|
||||||
)),
|
)),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
|
|
@ -594,6 +594,13 @@ impl IdentId {
|
||||||
pub const fn index(self) -> usize {
|
pub const fn index(self) -> usize {
|
||||||
self.0 as usize
|
self.0 as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The index is not guaranteed to know to exist.
|
||||||
|
pub unsafe fn from_index(index: u32) -> Self {
|
||||||
|
Self(index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores a mapping between Ident and IdentId.
|
/// Stores a mapping between Ident and IdentId.
|
||||||
|
|
|
@ -162,9 +162,15 @@ impl<'a> DeclarationToIndex<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let similar = self
|
||||||
|
.elements
|
||||||
|
.iter()
|
||||||
|
.filter_map(|((s, lay), _)| if *s == needle_symbol { Some(lay) } else { None })
|
||||||
|
.collect::<std::vec::Vec<_>>();
|
||||||
unreachable!(
|
unreachable!(
|
||||||
"symbol/layout {:?} {:#?} combo must be in DeclarationToIndex",
|
"symbol/layout {:?} {:#?} combo must be in DeclarationToIndex\nHowever {} similar layouts were found:\n{:#?}",
|
||||||
needle_symbol, needle_layout
|
needle_symbol, needle_layout, similar.len(), similar
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -942,7 +948,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
||||||
|
|
||||||
ListIsUnique => arena.alloc_slice_copy(&[borrowed]),
|
ListIsUnique => arena.alloc_slice_copy(&[borrowed]),
|
||||||
|
|
||||||
Dbg => arena.alloc_slice_copy(&[borrowed]),
|
Dbg => arena.alloc_slice_copy(&[borrowed, /* dbg-spec-var */ irrelevant]),
|
||||||
|
|
||||||
BoxExpr | UnboxExpr => {
|
BoxExpr | UnboxExpr => {
|
||||||
unreachable!("These lowlevel operations are turned into mono Expr's")
|
unreachable!("These lowlevel operations are turned into mono Expr's")
|
||||||
|
|
|
@ -309,14 +309,14 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
||||||
condition,
|
condition,
|
||||||
region: _,
|
region: _,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables: _,
|
||||||
remainder,
|
remainder,
|
||||||
}
|
}
|
||||||
| &Stmt::ExpectFx {
|
| &Stmt::ExpectFx {
|
||||||
condition,
|
condition,
|
||||||
region: _,
|
region: _,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables: _,
|
||||||
remainder,
|
remainder,
|
||||||
} => {
|
} => {
|
||||||
self.check_sym_layout(
|
self.check_sym_layout(
|
||||||
|
@ -324,8 +324,8 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
||||||
Layout::Builtin(Builtin::Bool),
|
Layout::Builtin(Builtin::Bool),
|
||||||
UseKind::ExpectCond,
|
UseKind::ExpectCond,
|
||||||
);
|
);
|
||||||
for (sym, lay) in lookups.iter().zip(layouts) {
|
for sym in lookups.iter() {
|
||||||
self.check_sym_layout(*sym, *lay, UseKind::ExpectLookup);
|
self.check_sym_exists(*sym);
|
||||||
}
|
}
|
||||||
self.check_stmt(remainder);
|
self.check_stmt(remainder);
|
||||||
}
|
}
|
||||||
|
|
|
@ -555,7 +555,13 @@ impl<'a, 'i> Context<'a, 'i> {
|
||||||
match &call_type {
|
match &call_type {
|
||||||
LowLevel { op, .. } => {
|
LowLevel { op, .. } => {
|
||||||
let ps = crate::borrow::lowlevel_borrow_signature(self.arena, *op);
|
let ps = crate::borrow::lowlevel_borrow_signature(self.arena, *op);
|
||||||
let b = self.add_dec_after_lowlevel(arguments, ps, b, b_live_vars);
|
let b = match op {
|
||||||
|
roc_module::low_level::LowLevel::Dbg => {
|
||||||
|
// NB(dbg-spec-var) second var is the Variable
|
||||||
|
self.add_dec_after_lowlevel(&arguments[..1], ps, b, b_live_vars)
|
||||||
|
}
|
||||||
|
_ => self.add_dec_after_lowlevel(arguments, ps, b, b_live_vars),
|
||||||
|
};
|
||||||
|
|
||||||
let v = Expr::Call(crate::ir::Call {
|
let v = Expr::Call(crate::ir::Call {
|
||||||
call_type,
|
call_type,
|
||||||
|
@ -1199,7 +1205,7 @@ impl<'a, 'i> Context<'a, 'i> {
|
||||||
condition,
|
condition,
|
||||||
region,
|
region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
} => {
|
} => {
|
||||||
let (b, mut b_live_vars) = self.visit_stmt(codegen, remainder);
|
let (b, mut b_live_vars) = self.visit_stmt(codegen, remainder);
|
||||||
|
|
||||||
|
@ -1207,7 +1213,7 @@ impl<'a, 'i> Context<'a, 'i> {
|
||||||
condition: *condition,
|
condition: *condition,
|
||||||
region: *region,
|
region: *region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder: b,
|
remainder: b,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1223,7 +1229,7 @@ impl<'a, 'i> Context<'a, 'i> {
|
||||||
condition,
|
condition,
|
||||||
region,
|
region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
} => {
|
} => {
|
||||||
let (b, mut b_live_vars) = self.visit_stmt(codegen, remainder);
|
let (b, mut b_live_vars) = self.visit_stmt(codegen, remainder);
|
||||||
|
|
||||||
|
@ -1231,7 +1237,7 @@ impl<'a, 'i> Context<'a, 'i> {
|
||||||
condition: *condition,
|
condition: *condition,
|
||||||
region: *region,
|
region: *region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder: b,
|
remainder: b,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -27,14 +27,14 @@ use roc_late_solve::storage::{ExternalModuleStorage, ExternalModuleStorageSnapsh
|
||||||
use roc_late_solve::{resolve_ability_specialization, AbilitiesView, Resolved, UnificationFailed};
|
use roc_late_solve::{resolve_ability_specialization, AbilitiesView, Resolved, UnificationFailed};
|
||||||
use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
|
use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
|
||||||
use roc_module::low_level::LowLevel;
|
use roc_module::low_level::LowLevel;
|
||||||
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
use roc_module::symbol::{IdentId, IdentIds, ModuleId, Symbol};
|
||||||
use roc_problem::can::{RuntimeError, ShadowKind};
|
use roc_problem::can::{RuntimeError, ShadowKind};
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_std::RocDec;
|
use roc_std::RocDec;
|
||||||
use roc_target::TargetInfo;
|
use roc_target::TargetInfo;
|
||||||
use roc_types::subs::{
|
use roc_types::subs::{
|
||||||
instantiate_rigids, Content, ExhaustiveMark, FlatType, RedundantMark, StorageSubs, Subs,
|
instantiate_rigids, storage_copy_var_to, Content, ExhaustiveMark, FlatType, RedundantMark,
|
||||||
Variable, VariableSubsSlice,
|
StorageSubs, Subs, Variable, VariableSubsSlice,
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder};
|
use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder};
|
||||||
|
@ -1465,6 +1465,9 @@ impl<'a> Specializations<'a> {
|
||||||
pub struct Env<'a, 'i> {
|
pub struct Env<'a, 'i> {
|
||||||
pub arena: &'a Bump,
|
pub arena: &'a Bump,
|
||||||
pub subs: &'i mut Subs,
|
pub subs: &'i mut Subs,
|
||||||
|
/// [Subs] to write specialized variables of lookups in expects.
|
||||||
|
/// [None] if this module doesn't produce any expects.
|
||||||
|
pub expectation_subs: Option<&'i mut Subs>,
|
||||||
pub home: ModuleId,
|
pub home: ModuleId,
|
||||||
pub ident_ids: &'i mut IdentIds,
|
pub ident_ids: &'i mut IdentIds,
|
||||||
pub target_info: TargetInfo,
|
pub target_info: TargetInfo,
|
||||||
|
@ -1601,6 +1604,9 @@ pub fn cond<'a>(
|
||||||
|
|
||||||
pub type Stores<'a> = &'a [(Symbol, Layout<'a>, Expr<'a>)];
|
pub type Stores<'a> = &'a [(Symbol, Layout<'a>, Expr<'a>)];
|
||||||
|
|
||||||
|
/// The specialized type of a lookup. Represented as a type-variable.
|
||||||
|
pub type LookupType = Variable;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Stmt<'a> {
|
pub enum Stmt<'a> {
|
||||||
Let(Symbol, Expr<'a>, Layout<'a>, &'a Stmt<'a>),
|
Let(Symbol, Expr<'a>, Layout<'a>, &'a Stmt<'a>),
|
||||||
|
@ -1622,7 +1628,7 @@ pub enum Stmt<'a> {
|
||||||
condition: Symbol,
|
condition: Symbol,
|
||||||
region: Region,
|
region: Region,
|
||||||
lookups: &'a [Symbol],
|
lookups: &'a [Symbol],
|
||||||
layouts: &'a [Layout<'a>],
|
variables: &'a [LookupType],
|
||||||
/// what happens after the expect
|
/// what happens after the expect
|
||||||
remainder: &'a Stmt<'a>,
|
remainder: &'a Stmt<'a>,
|
||||||
},
|
},
|
||||||
|
@ -1630,7 +1636,7 @@ pub enum Stmt<'a> {
|
||||||
condition: Symbol,
|
condition: Symbol,
|
||||||
region: Region,
|
region: Region,
|
||||||
lookups: &'a [Symbol],
|
lookups: &'a [Symbol],
|
||||||
layouts: &'a [Layout<'a>],
|
variables: &'a [LookupType],
|
||||||
/// what happens after the expect
|
/// what happens after the expect
|
||||||
remainder: &'a Stmt<'a>,
|
remainder: &'a Stmt<'a>,
|
||||||
},
|
},
|
||||||
|
@ -6570,13 +6576,14 @@ pub fn from_can<'a>(
|
||||||
let cond_symbol = env.unique_symbol();
|
let cond_symbol = env.unique_symbol();
|
||||||
|
|
||||||
let mut lookups = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
|
let mut lookups = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
|
||||||
let mut layouts = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
|
let mut lookup_variables = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
|
||||||
|
let mut specialized_variables = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
|
||||||
|
|
||||||
for ExpectLookup {
|
for ExpectLookup {
|
||||||
symbol,
|
symbol,
|
||||||
var,
|
var,
|
||||||
ability_info,
|
ability_info,
|
||||||
} in lookups_in_cond
|
} in lookups_in_cond.iter().copied()
|
||||||
{
|
{
|
||||||
let symbol = match ability_info {
|
let symbol = match ability_info {
|
||||||
Some(specialization_id) => late_resolve_ability_specialization(
|
Some(specialization_id) => late_resolve_ability_specialization(
|
||||||
|
@ -6587,20 +6594,28 @@ pub fn from_can<'a>(
|
||||||
),
|
),
|
||||||
None => symbol,
|
None => symbol,
|
||||||
};
|
};
|
||||||
let res_layout = layout_cache.from_var(env.arena, var, env.subs);
|
|
||||||
let layout = return_on_layout_error!(env, res_layout, "Expect");
|
let expectation_subs = env
|
||||||
if !matches!(layout, Layout::LambdaSet(..)) {
|
.expectation_subs
|
||||||
|
.as_deref_mut()
|
||||||
|
.expect("if expects are compiled, their subs should be available");
|
||||||
|
let spec_var = expectation_subs.fresh_unnamed_flex_var();
|
||||||
|
|
||||||
|
if !env.subs.is_function(var) {
|
||||||
// Exclude functions from lookups
|
// Exclude functions from lookups
|
||||||
lookups.push(symbol);
|
lookups.push(symbol);
|
||||||
layouts.push(layout);
|
lookup_variables.push(var);
|
||||||
|
specialized_variables.push(spec_var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let specialized_variables = specialized_variables.into_bump_slice();
|
||||||
|
|
||||||
let mut stmt = Stmt::Expect {
|
let mut stmt = Stmt::Expect {
|
||||||
condition: cond_symbol,
|
condition: cond_symbol,
|
||||||
region: loc_condition.region,
|
region: loc_condition.region,
|
||||||
lookups: lookups.into_bump_slice(),
|
lookups: lookups.into_bump_slice(),
|
||||||
layouts: layouts.into_bump_slice(),
|
variables: specialized_variables,
|
||||||
remainder: env.arena.alloc(rest),
|
remainder: env.arena.alloc(rest),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6614,6 +6629,10 @@ pub fn from_can<'a>(
|
||||||
env.arena.alloc(stmt),
|
env.arena.alloc(stmt),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Now that the condition has been specialized, export the specialized types of our
|
||||||
|
// lookups into the expectation subs.
|
||||||
|
store_specialized_expectation_lookups(env, lookup_variables, specialized_variables);
|
||||||
|
|
||||||
stmt
|
stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6626,13 +6645,14 @@ pub fn from_can<'a>(
|
||||||
let cond_symbol = env.unique_symbol();
|
let cond_symbol = env.unique_symbol();
|
||||||
|
|
||||||
let mut lookups = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
|
let mut lookups = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
|
||||||
let mut layouts = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
|
let mut lookup_variables = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
|
||||||
|
let mut specialized_variables = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
|
||||||
|
|
||||||
for ExpectLookup {
|
for ExpectLookup {
|
||||||
symbol,
|
symbol,
|
||||||
var,
|
var,
|
||||||
ability_info,
|
ability_info,
|
||||||
} in lookups_in_cond
|
} in lookups_in_cond.iter().copied()
|
||||||
{
|
{
|
||||||
let symbol = match ability_info {
|
let symbol = match ability_info {
|
||||||
Some(specialization_id) => late_resolve_ability_specialization(
|
Some(specialization_id) => late_resolve_ability_specialization(
|
||||||
|
@ -6643,20 +6663,28 @@ pub fn from_can<'a>(
|
||||||
),
|
),
|
||||||
None => symbol,
|
None => symbol,
|
||||||
};
|
};
|
||||||
let res_layout = layout_cache.from_var(env.arena, var, env.subs);
|
|
||||||
let layout = return_on_layout_error!(env, res_layout, "Expect");
|
let expectation_subs = env
|
||||||
if !matches!(layout, Layout::LambdaSet(..)) {
|
.expectation_subs
|
||||||
|
.as_deref_mut()
|
||||||
|
.expect("if expects are compiled, their subs should be available");
|
||||||
|
let spec_var = expectation_subs.fresh_unnamed_flex_var();
|
||||||
|
|
||||||
|
if !env.subs.is_function(var) {
|
||||||
// Exclude functions from lookups
|
// Exclude functions from lookups
|
||||||
lookups.push(symbol);
|
lookups.push(symbol);
|
||||||
layouts.push(layout);
|
lookup_variables.push(var);
|
||||||
|
specialized_variables.push(spec_var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let specialized_variables = specialized_variables.into_bump_slice();
|
||||||
|
|
||||||
let mut stmt = Stmt::ExpectFx {
|
let mut stmt = Stmt::ExpectFx {
|
||||||
condition: cond_symbol,
|
condition: cond_symbol,
|
||||||
region: loc_condition.region,
|
region: loc_condition.region,
|
||||||
lookups: lookups.into_bump_slice(),
|
lookups: lookups.into_bump_slice(),
|
||||||
layouts: layouts.into_bump_slice(),
|
variables: specialized_variables,
|
||||||
remainder: env.arena.alloc(rest),
|
remainder: env.arena.alloc(rest),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6670,6 +6698,8 @@ pub fn from_can<'a>(
|
||||||
env.arena.alloc(stmt),
|
env.arena.alloc(stmt),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
store_specialized_expectation_lookups(env, lookup_variables, specialized_variables);
|
||||||
|
|
||||||
stmt
|
stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6681,12 +6711,23 @@ pub fn from_can<'a>(
|
||||||
} => {
|
} => {
|
||||||
let rest = from_can(env, variable, loc_continuation.value, procs, layout_cache);
|
let rest = from_can(env, variable, loc_continuation.value, procs, layout_cache);
|
||||||
|
|
||||||
|
let spec_var = env
|
||||||
|
.expectation_subs
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.fresh_unnamed_flex_var();
|
||||||
|
// HACK(dbg-spec-var): pass the specialized type variable along injected into a fake symbol
|
||||||
|
let dbg_spec_var_symbol = Symbol::new(ModuleId::ATTR, unsafe {
|
||||||
|
IdentId::from_index(spec_var.index())
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: need to store the specialized variable of this dbg in the expectation_subs
|
||||||
let call = crate::ir::Call {
|
let call = crate::ir::Call {
|
||||||
call_type: CallType::LowLevel {
|
call_type: CallType::LowLevel {
|
||||||
op: LowLevel::Dbg,
|
op: LowLevel::Dbg,
|
||||||
update_mode: env.next_update_mode_id(),
|
update_mode: env.next_update_mode_id(),
|
||||||
},
|
},
|
||||||
arguments: env.arena.alloc([dbg_symbol]),
|
arguments: env.arena.alloc([dbg_symbol, dbg_spec_var_symbol]),
|
||||||
};
|
};
|
||||||
|
|
||||||
let dbg_layout = layout_cache
|
let dbg_layout = layout_cache
|
||||||
|
@ -6714,6 +6755,10 @@ pub fn from_can<'a>(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now that the dbg value has been specialized, export its specialized type into the
|
||||||
|
// expectations subs.
|
||||||
|
store_specialized_expectation_lookups(env, [variable], &[spec_var]);
|
||||||
|
|
||||||
stmt
|
stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6752,6 +6797,21 @@ pub fn from_can<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn store_specialized_expectation_lookups(
|
||||||
|
env: &mut Env,
|
||||||
|
lookup_variables: impl IntoIterator<Item = Variable>,
|
||||||
|
specialized_variables: &[Variable],
|
||||||
|
) {
|
||||||
|
let subs = &env.subs;
|
||||||
|
let expectation_subs = env.expectation_subs.as_deref_mut().unwrap();
|
||||||
|
for (lookup_var, stored_var) in lookup_variables.into_iter().zip(specialized_variables) {
|
||||||
|
let stored_specialized_var =
|
||||||
|
storage_copy_var_to(&mut Default::default(), subs, expectation_subs, lookup_var);
|
||||||
|
let stored_specialized_desc = expectation_subs.get(stored_specialized_var);
|
||||||
|
expectation_subs.union(*stored_var, stored_specialized_var, stored_specialized_desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn to_opt_branches<'a>(
|
fn to_opt_branches<'a>(
|
||||||
env: &mut Env<'a, '_>,
|
env: &mut Env<'a, '_>,
|
||||||
procs: &mut Procs<'a>,
|
procs: &mut Procs<'a>,
|
||||||
|
@ -7082,7 +7142,7 @@ fn substitute_in_stmt_help<'a>(
|
||||||
condition,
|
condition,
|
||||||
region,
|
region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder,
|
remainder,
|
||||||
} => {
|
} => {
|
||||||
let new_remainder =
|
let new_remainder =
|
||||||
|
@ -7097,7 +7157,7 @@ fn substitute_in_stmt_help<'a>(
|
||||||
condition: substitute(subs, *condition).unwrap_or(*condition),
|
condition: substitute(subs, *condition).unwrap_or(*condition),
|
||||||
region: *region,
|
region: *region,
|
||||||
lookups: new_lookups.into_bump_slice(),
|
lookups: new_lookups.into_bump_slice(),
|
||||||
layouts,
|
variables,
|
||||||
remainder: new_remainder,
|
remainder: new_remainder,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7108,7 +7168,7 @@ fn substitute_in_stmt_help<'a>(
|
||||||
condition,
|
condition,
|
||||||
region,
|
region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder,
|
remainder,
|
||||||
} => {
|
} => {
|
||||||
let new_remainder =
|
let new_remainder =
|
||||||
|
@ -7123,7 +7183,7 @@ fn substitute_in_stmt_help<'a>(
|
||||||
condition: substitute(subs, *condition).unwrap_or(*condition),
|
condition: substitute(subs, *condition).unwrap_or(*condition),
|
||||||
region: *region,
|
region: *region,
|
||||||
lookups: new_lookups.into_bump_slice(),
|
lookups: new_lookups.into_bump_slice(),
|
||||||
layouts,
|
variables,
|
||||||
remainder: new_remainder,
|
remainder: new_remainder,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8234,7 +8294,46 @@ fn specialize_symbol<'a>(
|
||||||
Err(e) => return_on_layout_error_help!(env, e, "specialize_symbol"),
|
Err(e) => return_on_layout_error_help!(env, e, "specialize_symbol"),
|
||||||
};
|
};
|
||||||
|
|
||||||
if procs.is_imported_module_thunk(original) {
|
match raw {
|
||||||
|
RawFunctionLayout::Function(_, lambda_set, _)
|
||||||
|
if !procs.is_imported_module_thunk(original) =>
|
||||||
|
{
|
||||||
|
let lambda_name =
|
||||||
|
find_lambda_name(env, layout_cache, lambda_set, original, &[]);
|
||||||
|
|
||||||
|
debug_assert!(
|
||||||
|
lambda_name.no_captures(),
|
||||||
|
"imported functions are top-level and should never capture"
|
||||||
|
);
|
||||||
|
|
||||||
|
let function_ptr_layout = ProcLayout::from_raw(
|
||||||
|
env.arena,
|
||||||
|
&layout_cache.interner,
|
||||||
|
raw,
|
||||||
|
lambda_name.captures_niche(),
|
||||||
|
);
|
||||||
|
procs.insert_passed_by_name(
|
||||||
|
env,
|
||||||
|
arg_var,
|
||||||
|
lambda_name,
|
||||||
|
function_ptr_layout,
|
||||||
|
layout_cache,
|
||||||
|
);
|
||||||
|
|
||||||
|
construct_closure_data(
|
||||||
|
env,
|
||||||
|
procs,
|
||||||
|
layout_cache,
|
||||||
|
lambda_set,
|
||||||
|
lambda_name,
|
||||||
|
&[],
|
||||||
|
assign_to,
|
||||||
|
env.arena.alloc(result),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// This is an imported ZAT that returns either a value, or the closure
|
||||||
|
// data for a lambda set.
|
||||||
let layout = match raw {
|
let layout = match raw {
|
||||||
RawFunctionLayout::ZeroArgumentThunk(layout) => layout,
|
RawFunctionLayout::ZeroArgumentThunk(layout) => layout,
|
||||||
RawFunctionLayout::Function(_, lambda_set, _) => {
|
RawFunctionLayout::Function(_, lambda_set, _) => {
|
||||||
|
@ -8259,24 +8358,7 @@ fn specialize_symbol<'a>(
|
||||||
);
|
);
|
||||||
|
|
||||||
force_thunk(env, original, layout, assign_to, env.arena.alloc(result))
|
force_thunk(env, original, layout, assign_to, env.arena.alloc(result))
|
||||||
} else {
|
}
|
||||||
// Imported symbol, so it must have no captures niche (since
|
|
||||||
// top-levels can't capture)
|
|
||||||
let top_level = ProcLayout::from_raw(
|
|
||||||
env.arena,
|
|
||||||
&layout_cache.interner,
|
|
||||||
raw,
|
|
||||||
CapturesNiche::no_niche(),
|
|
||||||
);
|
|
||||||
procs.insert_passed_by_name(
|
|
||||||
env,
|
|
||||||
arg_var,
|
|
||||||
LambdaName::no_niche(original),
|
|
||||||
top_level,
|
|
||||||
layout_cache,
|
|
||||||
);
|
|
||||||
|
|
||||||
let_empty_struct(assign_to, env.arena.alloc(result))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2890,7 +2890,6 @@ impl<'a> Builtin<'a> {
|
||||||
use FloatWidth::*;
|
use FloatWidth::*;
|
||||||
|
|
||||||
match float_width {
|
match float_width {
|
||||||
F128 => alloc.text("Float128"),
|
|
||||||
F64 => alloc.text("Float64"),
|
F64 => alloc.text("Float64"),
|
||||||
F32 => alloc.text("Float32"),
|
F32 => alloc.text("Float32"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,7 +195,7 @@ fn function_s<'a, 'i>(
|
||||||
condition,
|
condition,
|
||||||
region,
|
region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder,
|
remainder,
|
||||||
} => {
|
} => {
|
||||||
let continuation: &Stmt = remainder;
|
let continuation: &Stmt = remainder;
|
||||||
|
@ -208,7 +208,7 @@ fn function_s<'a, 'i>(
|
||||||
condition: *condition,
|
condition: *condition,
|
||||||
region: *region,
|
region: *region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder: new_continuation,
|
remainder: new_continuation,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -220,7 +220,7 @@ fn function_s<'a, 'i>(
|
||||||
condition,
|
condition,
|
||||||
region,
|
region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder,
|
remainder,
|
||||||
} => {
|
} => {
|
||||||
let continuation: &Stmt = remainder;
|
let continuation: &Stmt = remainder;
|
||||||
|
@ -233,7 +233,7 @@ fn function_s<'a, 'i>(
|
||||||
condition: *condition,
|
condition: *condition,
|
||||||
region: *region,
|
region: *region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder: new_continuation,
|
remainder: new_continuation,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -442,7 +442,7 @@ fn function_d_main<'a, 'i>(
|
||||||
condition,
|
condition,
|
||||||
region,
|
region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder,
|
remainder,
|
||||||
} => {
|
} => {
|
||||||
let (b, found) = function_d_main(env, x, c, remainder);
|
let (b, found) = function_d_main(env, x, c, remainder);
|
||||||
|
@ -452,7 +452,7 @@ fn function_d_main<'a, 'i>(
|
||||||
condition: *condition,
|
condition: *condition,
|
||||||
region: *region,
|
region: *region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder: b,
|
remainder: b,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -464,7 +464,7 @@ fn function_d_main<'a, 'i>(
|
||||||
condition: *condition,
|
condition: *condition,
|
||||||
region: *region,
|
region: *region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder: b,
|
remainder: b,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -475,7 +475,7 @@ fn function_d_main<'a, 'i>(
|
||||||
condition,
|
condition,
|
||||||
region,
|
region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder,
|
remainder,
|
||||||
} => {
|
} => {
|
||||||
let (b, found) = function_d_main(env, x, c, remainder);
|
let (b, found) = function_d_main(env, x, c, remainder);
|
||||||
|
@ -485,7 +485,7 @@ fn function_d_main<'a, 'i>(
|
||||||
condition: *condition,
|
condition: *condition,
|
||||||
region: *region,
|
region: *region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder: b,
|
remainder: b,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -497,7 +497,7 @@ fn function_d_main<'a, 'i>(
|
||||||
condition: *condition,
|
condition: *condition,
|
||||||
region: *region,
|
region: *region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder: b,
|
remainder: b,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -660,7 +660,7 @@ fn function_r<'a, 'i>(env: &mut Env<'a, 'i>, stmt: &'a Stmt<'a>) -> &'a Stmt<'a>
|
||||||
condition,
|
condition,
|
||||||
region,
|
region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder,
|
remainder,
|
||||||
} => {
|
} => {
|
||||||
let b = function_r(env, remainder);
|
let b = function_r(env, remainder);
|
||||||
|
@ -669,7 +669,7 @@ fn function_r<'a, 'i>(env: &mut Env<'a, 'i>, stmt: &'a Stmt<'a>) -> &'a Stmt<'a>
|
||||||
condition: *condition,
|
condition: *condition,
|
||||||
region: *region,
|
region: *region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder: b,
|
remainder: b,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -680,7 +680,7 @@ fn function_r<'a, 'i>(env: &mut Env<'a, 'i>, stmt: &'a Stmt<'a>) -> &'a Stmt<'a>
|
||||||
condition,
|
condition,
|
||||||
region,
|
region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder,
|
remainder,
|
||||||
} => {
|
} => {
|
||||||
let b = function_r(env, remainder);
|
let b = function_r(env, remainder);
|
||||||
|
@ -689,7 +689,7 @@ fn function_r<'a, 'i>(env: &mut Env<'a, 'i>, stmt: &'a Stmt<'a>) -> &'a Stmt<'a>
|
||||||
condition: *condition,
|
condition: *condition,
|
||||||
region: *region,
|
region: *region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder: b,
|
remainder: b,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -253,7 +253,7 @@ fn insert_jumps<'a>(
|
||||||
condition,
|
condition,
|
||||||
region,
|
region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder,
|
remainder,
|
||||||
} => match insert_jumps(
|
} => match insert_jumps(
|
||||||
arena,
|
arena,
|
||||||
|
@ -267,7 +267,7 @@ fn insert_jumps<'a>(
|
||||||
condition: *condition,
|
condition: *condition,
|
||||||
region: *region,
|
region: *region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder: cont,
|
remainder: cont,
|
||||||
})),
|
})),
|
||||||
None => None,
|
None => None,
|
||||||
|
@ -277,7 +277,7 @@ fn insert_jumps<'a>(
|
||||||
condition,
|
condition,
|
||||||
region,
|
region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder,
|
remainder,
|
||||||
} => match insert_jumps(
|
} => match insert_jumps(
|
||||||
arena,
|
arena,
|
||||||
|
@ -291,7 +291,7 @@ fn insert_jumps<'a>(
|
||||||
condition: *condition,
|
condition: *condition,
|
||||||
region: *region,
|
region: *region,
|
||||||
lookups,
|
lookups,
|
||||||
layouts,
|
variables,
|
||||||
remainder: cont,
|
remainder: cont,
|
||||||
})),
|
})),
|
||||||
None => None,
|
None => None,
|
||||||
|
|
|
@ -262,6 +262,7 @@ mod solve_expr {
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct InferOptions {
|
struct InferOptions {
|
||||||
|
print_can_decls: bool,
|
||||||
print_only_under_alias: bool,
|
print_only_under_alias: bool,
|
||||||
allow_errors: bool,
|
allow_errors: bool,
|
||||||
}
|
}
|
||||||
|
@ -302,7 +303,20 @@ mod solve_expr {
|
||||||
let queries = parse_queries(&src);
|
let queries = parse_queries(&src);
|
||||||
assert!(!queries.is_empty(), "No queries provided!");
|
assert!(!queries.is_empty(), "No queries provided!");
|
||||||
|
|
||||||
let mut solved_queries = Vec::with_capacity(queries.len());
|
let mut output_parts = Vec::with_capacity(queries.len() + 2);
|
||||||
|
|
||||||
|
if options.print_can_decls {
|
||||||
|
use roc_can::debug::{pretty_print_declarations, PPCtx};
|
||||||
|
let ctx = PPCtx {
|
||||||
|
home,
|
||||||
|
interns: &interns,
|
||||||
|
print_lambda_names: true,
|
||||||
|
};
|
||||||
|
let pretty_decls = pretty_print_declarations(&ctx, &decls);
|
||||||
|
output_parts.push(pretty_decls);
|
||||||
|
output_parts.push("\n".to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
for TypeQuery(region) in queries.into_iter() {
|
for TypeQuery(region) in queries.into_iter() {
|
||||||
let start = region.start().offset;
|
let start = region.start().offset;
|
||||||
let end = region.end().offset;
|
let end = region.end().offset;
|
||||||
|
@ -340,12 +354,12 @@ mod solve_expr {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
solved_queries.push(elaborated);
|
output_parts.push(elaborated);
|
||||||
}
|
}
|
||||||
|
|
||||||
let pretty_solved_queries = solved_queries.join("\n");
|
let pretty_output = output_parts.join("\n");
|
||||||
|
|
||||||
expected(&pretty_solved_queries);
|
expected(&pretty_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! infer_queries {
|
macro_rules! infer_queries {
|
||||||
|
@ -6720,9 +6734,9 @@ mod solve_expr {
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
@r#"
|
@r#"
|
||||||
A#id(5) : {} -[[id(5)]]-> ({} -[[8(8)]]-> {})
|
A#id(5) : {} -[[id(5)]]-> ({} -[[8]]-> {})
|
||||||
Id#id(3) : a -[[] + a:id(3):1]-> ({} -[[] + a:id(3):2]-> a) | a has Id
|
Id#id(3) : a -[[] + a:id(3):1]-> ({} -[[] + a:id(3):2]-> a) | a has Id
|
||||||
alias : {} -[[id(5)]]-> ({} -[[8(8)]]-> {})
|
alias : {} -[[id(5)]]-> ({} -[[8]]-> {})
|
||||||
"#
|
"#
|
||||||
print_only_under_alias: true
|
print_only_under_alias: true
|
||||||
)
|
)
|
||||||
|
@ -6751,8 +6765,8 @@ mod solve_expr {
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
@r#"
|
@r#"
|
||||||
A#id(5) : {} -[[id(5)]]-> ({} -[[8(8)]]-> {})
|
A#id(5) : {} -[[id(5)]]-> ({} -[[8]]-> {})
|
||||||
it : {} -[[8(8)]]-> {}
|
it : {} -[[8]]-> {}
|
||||||
"#
|
"#
|
||||||
print_only_under_alias: true
|
print_only_under_alias: true
|
||||||
)
|
)
|
||||||
|
@ -6782,8 +6796,8 @@ mod solve_expr {
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
@r#"
|
@r#"
|
||||||
A#id(5) : {} -[[id(5)]]-> ({} -[[8(8)]]-> {})
|
A#id(5) : {} -[[id(5)]]-> ({} -[[8]]-> {})
|
||||||
A#id(5) : {} -[[id(5)]]-> ({} -[[8(8)]]-> {})
|
A#id(5) : {} -[[id(5)]]-> ({} -[[8]]-> {})
|
||||||
"#
|
"#
|
||||||
print_only_under_alias: true
|
print_only_under_alias: true
|
||||||
)
|
)
|
||||||
|
@ -6903,7 +6917,7 @@ mod solve_expr {
|
||||||
#^^^^^^^^^^^^^^^^^^^^^^{-1}
|
#^^^^^^^^^^^^^^^^^^^^^^{-1}
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
@r#"[\{} -> {}, \{} -> {}] : List ({}* -[[1(1), 2(2)]]-> {})"#
|
@r###"[\{} -> {}, \{} -> {}] : List ({}* -[[1, 2]]-> {})"###
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7078,7 +7092,7 @@ mod solve_expr {
|
||||||
#^^^{-1}
|
#^^^{-1}
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
@r#"fun : {} -[[thunk(9) (({} -[[15(15)]]-> { s1 : Str })) ({ s1 : Str } -[[g(4)]]-> ({} -[[13(13) Str]]-> Str)), thunk(9) (({} -[[14(14)]]-> Str)) (Str -[[f(3)]]-> ({} -[[11(11)]]-> Str))]]-> Str"#
|
@r#"fun : {} -[[thunk(9) (({} -[[15]]-> { s1 : Str })) ({ s1 : Str } -[[g(4)]]-> ({} -[[13 Str]]-> Str)), thunk(9) (({} -[[14]]-> Str)) (Str -[[f(3)]]-> ({} -[[11]]-> Str))]]-> Str"#
|
||||||
print_only_under_alias: true
|
print_only_under_alias: true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -7323,9 +7337,9 @@ mod solve_expr {
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
@r###"
|
@r###"
|
||||||
Fo#f(7) : Fo, b -[[f(7)]]-> ({} -[[13(13) b]]-> ({} -[[] + b:g(4):2]-> {})) | b has G
|
Fo#f(7) : Fo, b -[[f(7)]]-> ({} -[[13 b]]-> ({} -[[] + b:g(4):2]-> {})) | b has G
|
||||||
Go#g(8) : Go -[[g(8)]]-> ({} -[[14(14)]]-> {})
|
Go#g(8) : Go -[[g(8)]]-> ({} -[[14]]-> {})
|
||||||
Fo#f(7) : Fo, Go -[[f(7)]]-> ({} -[[13(13) Go]]-> ({} -[[14(14)]]-> {}))
|
Fo#f(7) : Fo, Go -[[f(7)]]-> ({} -[[13 Go]]-> ({} -[[14]]-> {}))
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -7692,7 +7706,7 @@ mod solve_expr {
|
||||||
@r###"
|
@r###"
|
||||||
const : Str -[[const(2)]]-> (Str -[[closCompose(7) (Str -a-> Str) (Str -[[]]-> Str), closConst(10) Str] as a]-> Str)
|
const : Str -[[const(2)]]-> (Str -[[closCompose(7) (Str -a-> Str) (Str -[[]]-> Str), closConst(10) Str] as a]-> Str)
|
||||||
compose : (Str -a-> Str), (Str -[[]]-> Str) -[[compose(1)]]-> (Str -a-> Str)
|
compose : (Str -a-> Str), (Str -[[]]-> Str) -[[compose(1)]]-> (Str -a-> Str)
|
||||||
\c1, c2 -> compose c1 c2 : (Str -a-> Str), (Str -[[]]-> Str) -[[11(11)]]-> (Str -a-> Str)
|
\c1, c2 -> compose c1 c2 : (Str -a-> Str), (Str -[[]]-> Str) -[[11]]-> (Str -a-> Str)
|
||||||
res : Str -[[closCompose(7) (Str -a-> Str) (Str -[[]]-> Str), closConst(10) Str] as a]-> Str
|
res : Str -[[closCompose(7) (Str -a-> Str) (Str -[[]]-> Str), closConst(10) Str] as a]-> Str
|
||||||
res : Str -[[closCompose(7) (Str -a-> Str) (Str -[[]]-> Str), closConst(10) Str] as a]-> Str
|
res : Str -[[closCompose(7) (Str -a-> Str) (Str -[[]]-> Str), closConst(10) Str] as a]-> Str
|
||||||
"###
|
"###
|
||||||
|
@ -8077,7 +8091,7 @@ mod solve_expr {
|
||||||
# ^^^^^^^^^^^^^^
|
# ^^^^^^^^^^^^^^
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
@"N#Decode.decoder(3) : List U8, fmt -[[7(7)]]-> { rest : List U8, result : [Err [TooShort], Ok U8] } | fmt has DecoderFormatting"
|
@"N#Decode.decoder(3) : List U8, fmt -[[7]]-> { rest : List U8, result : [Err [TooShort], Ok U8] } | fmt has DecoderFormatting"
|
||||||
print_only_under_alias: true
|
print_only_under_alias: true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -8360,7 +8374,7 @@ mod solve_expr {
|
||||||
),
|
),
|
||||||
@r###"
|
@r###"
|
||||||
isEqQ : ({} -[[]]-> Str), ({} -[[]]-> Str) -[[isEqQ(2)]]-> [False, True]
|
isEqQ : ({} -[[]]-> Str), ({} -[[]]-> Str) -[[isEqQ(2)]]-> [False, True]
|
||||||
isEqQ : ({} -[[6(6), 7(7)]]-> Str), ({} -[[6(6), 7(7)]]-> Str) -[[isEqQ(2)]]-> [False, True]
|
isEqQ : ({} -[[6, 7]]-> Str), ({} -[[6, 7]]-> Str) -[[isEqQ(2)]]-> [False, True]
|
||||||
"###
|
"###
|
||||||
print_only_under_alias: true
|
print_only_under_alias: true
|
||||||
);
|
);
|
||||||
|
@ -8456,4 +8470,82 @@ mod solve_expr {
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn disjoint_nested_lambdas_result_in_disjoint_parents_issue_4712() {
|
||||||
|
infer_queries!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
|
Parser a : {} -> a
|
||||||
|
|
||||||
|
v1 : {}
|
||||||
|
v1 = {}
|
||||||
|
|
||||||
|
v2 : Str
|
||||||
|
v2 = ""
|
||||||
|
|
||||||
|
apply : Parser (a -> Str), a -> Parser Str
|
||||||
|
apply = \fnParser, valParser ->
|
||||||
|
\{} ->
|
||||||
|
(fnParser {}) (valParser)
|
||||||
|
|
||||||
|
map : a, (a -> Str) -> Parser Str
|
||||||
|
map = \simpleParser, transform ->
|
||||||
|
apply (\{} -> transform) simpleParser
|
||||||
|
|
||||||
|
parseInput = \{} ->
|
||||||
|
when [ map v1 (\{} -> ""), map v2 (\s -> s) ] is
|
||||||
|
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
_ -> ""
|
||||||
|
|
||||||
|
main = parseInput {} == ""
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
@r###"
|
||||||
|
v1 = {}
|
||||||
|
|
||||||
|
v2 = ""
|
||||||
|
|
||||||
|
apply = \fnParser, valParser-> \{} -[9]-> (fnParser {}) valParser
|
||||||
|
|
||||||
|
map = \simpleParser, transform-> apply \{} -[12]-> transform simpleParser
|
||||||
|
|
||||||
|
parseInput =
|
||||||
|
\{}->
|
||||||
|
when [
|
||||||
|
map v1 \{} -[13]-> "",
|
||||||
|
map v2 \s -[14]-> s,
|
||||||
|
] is
|
||||||
|
_ -> ""
|
||||||
|
|
||||||
|
main = Bool.isEq (parseInput {}) ""
|
||||||
|
|
||||||
|
|
||||||
|
[ map v1 (\{} -> ""), map v2 (\s -> s) ] : List (({} -[[9 (({} -[[12 (Str -[[14]]-> Str)]]-> (Str -[[14]]-> Str))) Str, 9 (({} -[[12 ({} -[[13]]-> Str)]]-> ({} -[[13]]-> Str))) {}]]-> Str))
|
||||||
|
"###
|
||||||
|
print_only_under_alias: true
|
||||||
|
print_can_decls: true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn constrain_dbg_flex_var() {
|
||||||
|
infer_queries!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
|
polyDbg = \x ->
|
||||||
|
#^^^^^^^{-1}
|
||||||
|
dbg x
|
||||||
|
x
|
||||||
|
|
||||||
|
main = polyDbg ""
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
@"polyDbg : a -[[polyDbg(1)]]-> a"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,9 +103,9 @@ fn list() {
|
||||||
# Specialization lambda sets:
|
# Specialization lambda sets:
|
||||||
# @<1>: [[custom(3)]]
|
# @<1>: [[custom(3)]]
|
||||||
#Derived.decoder_list =
|
#Derived.decoder_list =
|
||||||
Decode.custom
|
custom
|
||||||
\#Derived.bytes, #Derived.fmt ->
|
\#Derived.bytes, #Derived.fmt ->
|
||||||
Decode.decodeWith #Derived.bytes (Decode.list Decode.decoder) #Derived.fmt
|
decodeWith #Derived.bytes (list decoder) #Derived.fmt
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -121,21 +121,18 @@ fn record_2_fields() {
|
||||||
# Specialization lambda sets:
|
# Specialization lambda sets:
|
||||||
# @<1>: [[custom(22)]]
|
# @<1>: [[custom(22)]]
|
||||||
#Derived.decoder_{first,second} =
|
#Derived.decoder_{first,second} =
|
||||||
Decode.custom
|
custom
|
||||||
\#Derived.bytes3, #Derived.fmt3 ->
|
\#Derived.bytes3, #Derived.fmt3 ->
|
||||||
Decode.decodeWith
|
decodeWith
|
||||||
#Derived.bytes3
|
#Derived.bytes3
|
||||||
(Decode.record
|
(record
|
||||||
{ second: Err NoField, first: Err NoField }
|
{ second: Err NoField, first: Err NoField }
|
||||||
\#Derived.stateRecord2, #Derived.field ->
|
\#Derived.stateRecord2, #Derived.field ->
|
||||||
when #Derived.field is
|
when #Derived.field is
|
||||||
"first" ->
|
"first" ->
|
||||||
Keep (Decode.custom
|
Keep (custom
|
||||||
\#Derived.bytes, #Derived.fmt ->
|
\#Derived.bytes, #Derived.fmt ->
|
||||||
when Decode.decodeWith
|
when decodeWith #Derived.bytes decoder #Derived.fmt is
|
||||||
#Derived.bytes
|
|
||||||
Decode.decoder
|
|
||||||
#Derived.fmt is
|
|
||||||
#Derived.rec ->
|
#Derived.rec ->
|
||||||
{
|
{
|
||||||
result: when #Derived.rec.result is
|
result: when #Derived.rec.result is
|
||||||
|
@ -145,12 +142,9 @@ fn record_2_fields() {
|
||||||
rest: #Derived.rec.rest
|
rest: #Derived.rec.rest
|
||||||
})
|
})
|
||||||
"second" ->
|
"second" ->
|
||||||
Keep (Decode.custom
|
Keep (custom
|
||||||
\#Derived.bytes2, #Derived.fmt2 ->
|
\#Derived.bytes2, #Derived.fmt2 ->
|
||||||
when Decode.decodeWith
|
when decodeWith #Derived.bytes2 decoder #Derived.fmt2 is
|
||||||
#Derived.bytes2
|
|
||||||
Decode.decoder
|
|
||||||
#Derived.fmt2 is
|
|
||||||
#Derived.rec2 ->
|
#Derived.rec2 ->
|
||||||
{
|
{
|
||||||
result: when #Derived.rec2.result is
|
result: when #Derived.rec2.result is
|
||||||
|
|
|
@ -187,9 +187,9 @@ fn empty_record() {
|
||||||
# @<2>: [[custom(2) {}]]
|
# @<2>: [[custom(2) {}]]
|
||||||
#Derived.toEncoder_{} =
|
#Derived.toEncoder_{} =
|
||||||
\#Derived.rcd ->
|
\#Derived.rcd ->
|
||||||
Encode.custom
|
custom
|
||||||
\#Derived.bytes, #Derived.fmt ->
|
\#Derived.bytes, #Derived.fmt ->
|
||||||
Encode.appendWith #Derived.bytes (Encode.record []) #Derived.fmt
|
appendWith #Derived.bytes (record []) #Derived.fmt
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -207,9 +207,9 @@ fn zero_field_record() {
|
||||||
# @<2>: [[custom(2) {}]]
|
# @<2>: [[custom(2) {}]]
|
||||||
#Derived.toEncoder_{} =
|
#Derived.toEncoder_{} =
|
||||||
\#Derived.rcd ->
|
\#Derived.rcd ->
|
||||||
Encode.custom
|
custom
|
||||||
\#Derived.bytes, #Derived.fmt ->
|
\#Derived.bytes, #Derived.fmt ->
|
||||||
Encode.appendWith #Derived.bytes (Encode.record []) #Derived.fmt
|
appendWith #Derived.bytes (record []) #Derived.fmt
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -227,11 +227,11 @@ fn one_field_record() {
|
||||||
# @<2>: [[custom(2) { a : val }]] | val has Encoding
|
# @<2>: [[custom(2) { a : val }]] | val has Encoding
|
||||||
#Derived.toEncoder_{a} =
|
#Derived.toEncoder_{a} =
|
||||||
\#Derived.rcd ->
|
\#Derived.rcd ->
|
||||||
Encode.custom
|
custom
|
||||||
\#Derived.bytes, #Derived.fmt ->
|
\#Derived.bytes, #Derived.fmt ->
|
||||||
Encode.appendWith
|
appendWith
|
||||||
#Derived.bytes
|
#Derived.bytes
|
||||||
(Encode.record [{ value: Encode.toEncoder #Derived.rcd.a, key: "a" }])
|
(record [{ value: toEncoder #Derived.rcd.a, key: "a" }])
|
||||||
#Derived.fmt
|
#Derived.fmt
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
|
@ -250,14 +250,14 @@ fn two_field_record() {
|
||||||
# @<2>: [[custom(2) { a : val, b : val1 }]] | val has Encoding, val1 has Encoding
|
# @<2>: [[custom(2) { a : val, b : val1 }]] | val has Encoding, val1 has Encoding
|
||||||
#Derived.toEncoder_{a,b} =
|
#Derived.toEncoder_{a,b} =
|
||||||
\#Derived.rcd ->
|
\#Derived.rcd ->
|
||||||
Encode.custom
|
custom
|
||||||
\#Derived.bytes, #Derived.fmt ->
|
\#Derived.bytes, #Derived.fmt ->
|
||||||
Encode.appendWith
|
appendWith
|
||||||
#Derived.bytes
|
#Derived.bytes
|
||||||
(Encode.record
|
(record
|
||||||
[
|
[
|
||||||
{ value: Encode.toEncoder #Derived.rcd.a, key: "a" },
|
{ value: toEncoder #Derived.rcd.a, key: "a" },
|
||||||
{ value: Encode.toEncoder #Derived.rcd.b, key: "b" },
|
{ value: toEncoder #Derived.rcd.b, key: "b" },
|
||||||
])
|
])
|
||||||
#Derived.fmt
|
#Derived.fmt
|
||||||
"###
|
"###
|
||||||
|
@ -290,12 +290,12 @@ fn tag_one_label_zero_args() {
|
||||||
# @<2>: [[custom(2) [A]]]
|
# @<2>: [[custom(2) [A]]]
|
||||||
#Derived.toEncoder_[A 0] =
|
#Derived.toEncoder_[A 0] =
|
||||||
\#Derived.tag ->
|
\#Derived.tag ->
|
||||||
Encode.custom
|
custom
|
||||||
\#Derived.bytes, #Derived.fmt ->
|
\#Derived.bytes, #Derived.fmt ->
|
||||||
Encode.appendWith
|
appendWith
|
||||||
#Derived.bytes
|
#Derived.bytes
|
||||||
(when #Derived.tag is
|
(when #Derived.tag is
|
||||||
A -> Encode.tag "A" [])
|
A -> tag "A" [])
|
||||||
#Derived.fmt
|
#Derived.fmt
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
|
@ -314,18 +314,13 @@ fn tag_one_label_two_args() {
|
||||||
# @<2>: [[custom(4) [A val val1]]] | val has Encoding, val1 has Encoding
|
# @<2>: [[custom(4) [A val val1]]] | val has Encoding, val1 has Encoding
|
||||||
#Derived.toEncoder_[A 2] =
|
#Derived.toEncoder_[A 2] =
|
||||||
\#Derived.tag ->
|
\#Derived.tag ->
|
||||||
Encode.custom
|
custom
|
||||||
\#Derived.bytes, #Derived.fmt ->
|
\#Derived.bytes, #Derived.fmt ->
|
||||||
Encode.appendWith
|
appendWith
|
||||||
#Derived.bytes
|
#Derived.bytes
|
||||||
(when #Derived.tag is
|
(when #Derived.tag is
|
||||||
A #Derived.2 #Derived.3 ->
|
A #Derived.2 #Derived.3 ->
|
||||||
Encode.tag
|
tag "A" [toEncoder #Derived.2, toEncoder #Derived.3])
|
||||||
"A"
|
|
||||||
[
|
|
||||||
Encode.toEncoder #Derived.2,
|
|
||||||
Encode.toEncoder #Derived.3,
|
|
||||||
])
|
|
||||||
#Derived.fmt
|
#Derived.fmt
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
|
@ -347,20 +342,20 @@ fn tag_two_labels() {
|
||||||
# @<2>: [[custom(6) [A val val1 val1, B val1]]] | val has Encoding, val1 has Encoding
|
# @<2>: [[custom(6) [A val val1 val1, B val1]]] | val has Encoding, val1 has Encoding
|
||||||
#Derived.toEncoder_[A 3,B 1] =
|
#Derived.toEncoder_[A 3,B 1] =
|
||||||
\#Derived.tag ->
|
\#Derived.tag ->
|
||||||
Encode.custom
|
custom
|
||||||
\#Derived.bytes, #Derived.fmt ->
|
\#Derived.bytes, #Derived.fmt ->
|
||||||
Encode.appendWith
|
appendWith
|
||||||
#Derived.bytes
|
#Derived.bytes
|
||||||
(when #Derived.tag is
|
(when #Derived.tag is
|
||||||
A #Derived.2 #Derived.3 #Derived.4 ->
|
A #Derived.2 #Derived.3 #Derived.4 ->
|
||||||
Encode.tag
|
tag
|
||||||
"A"
|
"A"
|
||||||
[
|
[
|
||||||
Encode.toEncoder #Derived.2,
|
toEncoder #Derived.2,
|
||||||
Encode.toEncoder #Derived.3,
|
toEncoder #Derived.3,
|
||||||
Encode.toEncoder #Derived.4,
|
toEncoder #Derived.4,
|
||||||
]
|
]
|
||||||
B #Derived.5 -> Encode.tag "B" [Encode.toEncoder #Derived.5])
|
B #Derived.5 -> tag "B" [toEncoder #Derived.5])
|
||||||
#Derived.fmt
|
#Derived.fmt
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
|
@ -383,19 +378,14 @@ fn recursive_tag_union() {
|
||||||
# @<2>: [[custom(4) [Cons val val1, Nil]]] | val has Encoding, val1 has Encoding
|
# @<2>: [[custom(4) [Cons val val1, Nil]]] | val has Encoding, val1 has Encoding
|
||||||
#Derived.toEncoder_[Cons 2,Nil 0] =
|
#Derived.toEncoder_[Cons 2,Nil 0] =
|
||||||
\#Derived.tag ->
|
\#Derived.tag ->
|
||||||
Encode.custom
|
custom
|
||||||
\#Derived.bytes, #Derived.fmt ->
|
\#Derived.bytes, #Derived.fmt ->
|
||||||
Encode.appendWith
|
appendWith
|
||||||
#Derived.bytes
|
#Derived.bytes
|
||||||
(when #Derived.tag is
|
(when #Derived.tag is
|
||||||
Cons #Derived.2 #Derived.3 ->
|
Cons #Derived.2 #Derived.3 ->
|
||||||
Encode.tag
|
tag "Cons" [toEncoder #Derived.2, toEncoder #Derived.3]
|
||||||
"Cons"
|
Nil -> tag "Nil" [])
|
||||||
[
|
|
||||||
Encode.toEncoder #Derived.2,
|
|
||||||
Encode.toEncoder #Derived.3,
|
|
||||||
]
|
|
||||||
Nil -> Encode.tag "Nil" [])
|
|
||||||
#Derived.fmt
|
#Derived.fmt
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
|
@ -415,13 +405,11 @@ fn list() {
|
||||||
# @<2>: [[custom(4) (List val)]] | val has Encoding
|
# @<2>: [[custom(4) (List val)]] | val has Encoding
|
||||||
#Derived.toEncoder_list =
|
#Derived.toEncoder_list =
|
||||||
\#Derived.lst ->
|
\#Derived.lst ->
|
||||||
Encode.custom
|
custom
|
||||||
\#Derived.bytes, #Derived.fmt ->
|
\#Derived.bytes, #Derived.fmt ->
|
||||||
Encode.appendWith
|
appendWith
|
||||||
#Derived.bytes
|
#Derived.bytes
|
||||||
(Encode.list
|
(list #Derived.lst \#Derived.elem -> toEncoder #Derived.elem)
|
||||||
#Derived.lst
|
|
||||||
\#Derived.elem -> Encode.toEncoder #Derived.elem)
|
|
||||||
#Derived.fmt
|
#Derived.fmt
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
|
|
|
@ -178,7 +178,7 @@ fn one_field_record() {
|
||||||
# Specialization lambda sets:
|
# Specialization lambda sets:
|
||||||
# @<1>: [[hash_{a}(0)]]
|
# @<1>: [[hash_{a}(0)]]
|
||||||
#Derived.hash_{a} =
|
#Derived.hash_{a} =
|
||||||
\#Derived.hasher, #Derived.rcd -> Hash.hash #Derived.hasher #Derived.rcd.a
|
\#Derived.hasher, #Derived.rcd -> hash #Derived.hasher #Derived.rcd.a
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -195,7 +195,7 @@ fn two_field_record() {
|
||||||
# @<1>: [[hash_{a,b}(0)]]
|
# @<1>: [[hash_{a,b}(0)]]
|
||||||
#Derived.hash_{a,b} =
|
#Derived.hash_{a,b} =
|
||||||
\#Derived.hasher, #Derived.rcd ->
|
\#Derived.hasher, #Derived.rcd ->
|
||||||
Hash.hash (Hash.hash #Derived.hasher #Derived.rcd.a) #Derived.rcd.b
|
hash (hash #Derived.hasher #Derived.rcd.a) #Derived.rcd.b
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -227,7 +227,7 @@ fn tag_one_label_newtype() {
|
||||||
# @<1>: [[hash_[A 2](0)]]
|
# @<1>: [[hash_[A 2](0)]]
|
||||||
#Derived.hash_[A 2] =
|
#Derived.hash_[A 2] =
|
||||||
\#Derived.hasher, A #Derived.2 #Derived.3 ->
|
\#Derived.hasher, A #Derived.2 #Derived.3 ->
|
||||||
Hash.hash (Hash.hash #Derived.hasher #Derived.2) #Derived.3
|
hash (hash #Derived.hasher #Derived.2) #Derived.3
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -246,12 +246,10 @@ fn tag_two_labels() {
|
||||||
\#Derived.hasher, #Derived.union ->
|
\#Derived.hasher, #Derived.union ->
|
||||||
when #Derived.union is
|
when #Derived.union is
|
||||||
A #Derived.3 #Derived.4 #Derived.5 ->
|
A #Derived.3 #Derived.4 #Derived.5 ->
|
||||||
Hash.hash
|
hash
|
||||||
(Hash.hash
|
(hash (hash (addU8 #Derived.hasher 0) #Derived.3) #Derived.4)
|
||||||
(Hash.hash (Hash.addU8 #Derived.hasher 0) #Derived.3)
|
|
||||||
#Derived.4)
|
|
||||||
#Derived.5
|
#Derived.5
|
||||||
B #Derived.6 -> Hash.hash (Hash.addU8 #Derived.hasher 1) #Derived.6
|
B #Derived.6 -> hash (addU8 #Derived.hasher 1) #Derived.6
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -269,8 +267,8 @@ fn tag_two_labels_no_payloads() {
|
||||||
#Derived.hash_[A 0,B 0] =
|
#Derived.hash_[A 0,B 0] =
|
||||||
\#Derived.hasher, #Derived.union ->
|
\#Derived.hasher, #Derived.union ->
|
||||||
when #Derived.union is
|
when #Derived.union is
|
||||||
A -> Hash.addU8 #Derived.hasher 0
|
A -> addU8 #Derived.hasher 0
|
||||||
B -> Hash.addU8 #Derived.hasher 1
|
B -> addU8 #Derived.hasher 1
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -289,10 +287,8 @@ fn recursive_tag_union() {
|
||||||
\#Derived.hasher, #Derived.union ->
|
\#Derived.hasher, #Derived.union ->
|
||||||
when #Derived.union is
|
when #Derived.union is
|
||||||
Cons #Derived.3 #Derived.4 ->
|
Cons #Derived.3 #Derived.4 ->
|
||||||
Hash.hash
|
hash (hash (addU8 #Derived.hasher 0) #Derived.3) #Derived.4
|
||||||
(Hash.hash (Hash.addU8 #Derived.hasher 0) #Derived.3)
|
Nil -> addU8 #Derived.hasher 1
|
||||||
#Derived.4
|
|
||||||
Nil -> Hash.addU8 #Derived.hasher 1
|
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,5 +5,4 @@ mod encoding;
|
||||||
mod eq;
|
mod eq;
|
||||||
mod hash;
|
mod hash;
|
||||||
|
|
||||||
mod pretty_print;
|
|
||||||
mod util;
|
mod util;
|
||||||
|
|
|
@ -5,10 +5,10 @@ use bumpalo::Bump;
|
||||||
use roc_packaging::cache::RocCacheDir;
|
use roc_packaging::cache::RocCacheDir;
|
||||||
use ven_pretty::DocAllocator;
|
use ven_pretty::DocAllocator;
|
||||||
|
|
||||||
use crate::pretty_print::{pretty_print_def, Ctx};
|
|
||||||
use roc_can::{
|
use roc_can::{
|
||||||
abilities::{AbilitiesStore, SpecializationLambdaSets},
|
abilities::{AbilitiesStore, SpecializationLambdaSets},
|
||||||
constraint::Constraints,
|
constraint::Constraints,
|
||||||
|
debug::{pretty_print_def, PPCtx},
|
||||||
def::Def,
|
def::Def,
|
||||||
expr::Declarations,
|
expr::Declarations,
|
||||||
module::{
|
module::{
|
||||||
|
@ -529,8 +529,12 @@ where
|
||||||
interns.all_ident_ids.insert(DERIVED_MODULE, ident_ids);
|
interns.all_ident_ids.insert(DERIVED_MODULE, ident_ids);
|
||||||
DERIVED_MODULE.register_debug_idents(interns.all_ident_ids.get(&DERIVED_MODULE).unwrap());
|
DERIVED_MODULE.register_debug_idents(interns.all_ident_ids.get(&DERIVED_MODULE).unwrap());
|
||||||
|
|
||||||
let ctx = Ctx { interns: &interns };
|
let pp_ctx = PPCtx {
|
||||||
let derived_program = pretty_print_def(&ctx, &derived_def);
|
interns: &interns,
|
||||||
|
print_lambda_names: false,
|
||||||
|
home: builtin_module,
|
||||||
|
};
|
||||||
|
let derived_program = pretty_print_def(&pp_ctx, &derived_def);
|
||||||
|
|
||||||
check_derived_typechecks_and_golden(
|
check_derived_typechecks_and_golden(
|
||||||
derived_def,
|
derived_def,
|
||||||
|
|
|
@ -4107,3 +4107,41 @@ fn issue_4349() {
|
||||||
RocStr
|
RocStr
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn issue_4712() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
|
Parser a : {} -> a
|
||||||
|
|
||||||
|
v1 : {}
|
||||||
|
v1 = {}
|
||||||
|
|
||||||
|
v2 : Str
|
||||||
|
v2 = "cd"
|
||||||
|
|
||||||
|
apply : Parser (a -> Str), a -> Parser Str
|
||||||
|
apply = \fnParser, valParser ->
|
||||||
|
\{} ->
|
||||||
|
(fnParser {}) (valParser)
|
||||||
|
|
||||||
|
map : a, (a -> Str) -> Parser Str
|
||||||
|
map = \simpleParser, transform ->
|
||||||
|
apply (\{} -> transform) simpleParser
|
||||||
|
|
||||||
|
gen = \{} ->
|
||||||
|
[ map v1 (\{} -> "ab"), map v2 (\s -> s) ]
|
||||||
|
|> List.map (\f -> f {})
|
||||||
|
|> Str.joinWith ","
|
||||||
|
|
||||||
|
main = gen {}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
RocStr::from("ab,cd"),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -2083,3 +2083,53 @@ fn unify_types_with_fixed_fixpoints_outside_fixing_region() {
|
||||||
RocStr
|
RocStr
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn lambda_set_with_imported_toplevels_issue_4733() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
|
fn = \s ->
|
||||||
|
instr = if s == "*" then (Op Num.mul) else (Op Num.add)
|
||||||
|
|
||||||
|
Op op = instr
|
||||||
|
|
||||||
|
\a -> op a a
|
||||||
|
|
||||||
|
main = ((fn "*") 3) * ((fn "+") 5)
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
90,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn non_unary_union_with_lambda_set_with_imported_toplevels_issue_4733() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
|
fn = \s ->
|
||||||
|
instr =
|
||||||
|
if s == "*" then (Op Num.mul)
|
||||||
|
else if s == "+" then (Op Num.add)
|
||||||
|
else Noop
|
||||||
|
|
||||||
|
when instr is
|
||||||
|
Op op -> (\a -> op a a)
|
||||||
|
_ -> (\a -> a)
|
||||||
|
|
||||||
|
|
||||||
|
main = ((fn "*") 3) * ((fn "+") 5)
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
90,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
316
crates/compiler/test_mono/generated/issue_4749.txt
Normal file
316
crates/compiler/test_mono/generated/issue_4749.txt
Normal file
|
@ -0,0 +1,316 @@
|
||||||
|
procedure Bool.11 (#Attr.2, #Attr.3):
|
||||||
|
let Bool.23 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||||
|
dec #Attr.3;
|
||||||
|
dec #Attr.2;
|
||||||
|
ret Bool.23;
|
||||||
|
|
||||||
|
procedure Bool.11 (#Attr.2, #Attr.3):
|
||||||
|
let Bool.31 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||||
|
ret Bool.31;
|
||||||
|
|
||||||
|
procedure Bool.11 (#Attr.2, #Attr.3):
|
||||||
|
let Bool.38 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||||
|
ret Bool.38;
|
||||||
|
|
||||||
|
procedure Bool.12 (#Attr.2, #Attr.3):
|
||||||
|
let Bool.30 : Int1 = lowlevel NotEq #Attr.2 #Attr.3;
|
||||||
|
ret Bool.30;
|
||||||
|
|
||||||
|
procedure Bool.7 (Bool.19, Bool.20):
|
||||||
|
let Bool.29 : Int1 = CallByName Bool.12 Bool.19 Bool.20;
|
||||||
|
ret Bool.29;
|
||||||
|
|
||||||
|
procedure Decode.23 (Decode.94):
|
||||||
|
ret Decode.94;
|
||||||
|
|
||||||
|
procedure Decode.24 (Decode.95, Decode.114, Decode.97):
|
||||||
|
let Decode.127 : {List U8, [C {}, C Str]} = CallByName Json.293 Decode.95 Decode.97;
|
||||||
|
ret Decode.127;
|
||||||
|
|
||||||
|
procedure Decode.25 (Decode.98, Decode.99):
|
||||||
|
let Decode.126 : {} = CallByName Json.41;
|
||||||
|
let Decode.125 : {List U8, [C {}, C Str]} = CallByName Decode.24 Decode.98 Decode.126 Decode.99;
|
||||||
|
ret Decode.125;
|
||||||
|
|
||||||
|
procedure Decode.26 (Decode.100, Decode.101):
|
||||||
|
let Decode.115 : {List U8, [C {}, C Str]} = CallByName Decode.25 Decode.100 Decode.101;
|
||||||
|
let Decode.103 : List U8 = StructAtIndex 0 Decode.115;
|
||||||
|
inc Decode.103;
|
||||||
|
let Decode.102 : [C {}, C Str] = StructAtIndex 1 Decode.115;
|
||||||
|
inc Decode.102;
|
||||||
|
dec Decode.115;
|
||||||
|
let Decode.118 : Int1 = CallByName List.1 Decode.103;
|
||||||
|
if Decode.118 then
|
||||||
|
dec Decode.103;
|
||||||
|
let Decode.122 : U8 = 1i64;
|
||||||
|
let Decode.123 : U8 = GetTagId Decode.102;
|
||||||
|
let Decode.124 : Int1 = lowlevel Eq Decode.122 Decode.123;
|
||||||
|
if Decode.124 then
|
||||||
|
let Decode.104 : Str = UnionAtIndex (Id 1) (Index 0) Decode.102;
|
||||||
|
inc Decode.104;
|
||||||
|
dec Decode.102;
|
||||||
|
let Decode.119 : [C [C List U8, C ], C Str] = TagId(1) Decode.104;
|
||||||
|
ret Decode.119;
|
||||||
|
else
|
||||||
|
dec Decode.102;
|
||||||
|
let Decode.121 : [C List U8, C ] = TagId(1) ;
|
||||||
|
let Decode.120 : [C [C List U8, C ], C Str] = TagId(0) Decode.121;
|
||||||
|
ret Decode.120;
|
||||||
|
else
|
||||||
|
dec Decode.102;
|
||||||
|
let Decode.117 : [C List U8, C ] = TagId(0) Decode.103;
|
||||||
|
let Decode.116 : [C [C List U8, C ], C Str] = TagId(0) Decode.117;
|
||||||
|
ret Decode.116;
|
||||||
|
|
||||||
|
procedure Json.139 (Json.450, Json.451):
|
||||||
|
joinpoint Json.421 Json.418 Json.138:
|
||||||
|
let Json.141 : List U8 = StructAtIndex 0 Json.418;
|
||||||
|
inc Json.141;
|
||||||
|
let Json.140 : List U8 = StructAtIndex 1 Json.418;
|
||||||
|
inc Json.140;
|
||||||
|
dec Json.418;
|
||||||
|
let Json.422 : [C {}, C U8] = CallByName List.9 Json.141;
|
||||||
|
let Json.436 : U8 = 1i64;
|
||||||
|
let Json.437 : U8 = GetTagId Json.422;
|
||||||
|
let Json.438 : Int1 = lowlevel Eq Json.436 Json.437;
|
||||||
|
if Json.438 then
|
||||||
|
let Json.142 : U8 = UnionAtIndex (Id 1) (Index 0) Json.422;
|
||||||
|
let Json.424 : Int1 = CallByName Json.283 Json.142;
|
||||||
|
if Json.424 then
|
||||||
|
let Json.434 : U64 = 1i64;
|
||||||
|
let Json.430 : {List U8, List U8} = CallByName List.52 Json.141 Json.434;
|
||||||
|
let Json.431 : {} = Struct {};
|
||||||
|
let Json.428 : List U8 = CallByName Json.143 Json.430;
|
||||||
|
let Json.429 : List U8 = CallByName List.4 Json.140 Json.142;
|
||||||
|
let Json.426 : {List U8, List U8} = Struct {Json.428, Json.429};
|
||||||
|
jump Json.421 Json.426 Json.138;
|
||||||
|
else
|
||||||
|
let Json.423 : {List U8, List U8} = Struct {Json.141, Json.140};
|
||||||
|
ret Json.423;
|
||||||
|
else
|
||||||
|
let Json.435 : {List U8, List U8} = Struct {Json.141, Json.140};
|
||||||
|
ret Json.435;
|
||||||
|
in
|
||||||
|
jump Json.421 Json.450 Json.451;
|
||||||
|
|
||||||
|
procedure Json.143 (Json.432):
|
||||||
|
let Json.433 : List U8 = StructAtIndex 1 Json.432;
|
||||||
|
inc Json.433;
|
||||||
|
dec Json.432;
|
||||||
|
ret Json.433;
|
||||||
|
|
||||||
|
procedure Json.2 ():
|
||||||
|
let Json.396 : {} = Struct {};
|
||||||
|
ret Json.396;
|
||||||
|
|
||||||
|
procedure Json.22 (Json.137, Json.138):
|
||||||
|
let Json.440 : List U8 = Array [];
|
||||||
|
let Json.420 : {List U8, List U8} = Struct {Json.137, Json.440};
|
||||||
|
let Json.419 : {List U8, List U8} = CallByName Json.139 Json.420 Json.138;
|
||||||
|
ret Json.419;
|
||||||
|
|
||||||
|
procedure Json.283 (Json.284):
|
||||||
|
let Json.442 : U8 = 34i64;
|
||||||
|
let Json.441 : Int1 = CallByName Bool.7 Json.284 Json.442;
|
||||||
|
ret Json.441;
|
||||||
|
|
||||||
|
procedure Json.293 (Json.294, Json.399):
|
||||||
|
let Json.400 : {List U8, [C {}, C Str]} = CallByName Json.40 Json.294;
|
||||||
|
ret Json.400;
|
||||||
|
|
||||||
|
procedure Json.40 (Json.276):
|
||||||
|
let Json.446 : U64 = 1i64;
|
||||||
|
inc Json.276;
|
||||||
|
let Json.445 : {List U8, List U8} = CallByName List.52 Json.276 Json.446;
|
||||||
|
let Json.277 : List U8 = StructAtIndex 0 Json.445;
|
||||||
|
inc Json.277;
|
||||||
|
let Json.279 : List U8 = StructAtIndex 1 Json.445;
|
||||||
|
inc Json.279;
|
||||||
|
dec Json.445;
|
||||||
|
let Json.444 : U8 = 34i64;
|
||||||
|
let Json.443 : List U8 = Array [Json.444];
|
||||||
|
let Json.404 : Int1 = CallByName Bool.11 Json.277 Json.443;
|
||||||
|
dec Json.443;
|
||||||
|
dec Json.277;
|
||||||
|
if Json.404 then
|
||||||
|
dec Json.276;
|
||||||
|
let Json.417 : {} = Struct {};
|
||||||
|
let Json.416 : {List U8, List U8} = CallByName Json.22 Json.279 Json.417;
|
||||||
|
let Json.282 : List U8 = StructAtIndex 0 Json.416;
|
||||||
|
inc Json.282;
|
||||||
|
let Json.281 : List U8 = StructAtIndex 1 Json.416;
|
||||||
|
inc Json.281;
|
||||||
|
dec Json.416;
|
||||||
|
let Json.405 : [C {U64, U8}, C Str] = CallByName Str.9 Json.281;
|
||||||
|
let Json.413 : U8 = 1i64;
|
||||||
|
let Json.414 : U8 = GetTagId Json.405;
|
||||||
|
let Json.415 : Int1 = lowlevel Eq Json.413 Json.414;
|
||||||
|
if Json.415 then
|
||||||
|
let Json.285 : Str = UnionAtIndex (Id 1) (Index 0) Json.405;
|
||||||
|
inc Json.285;
|
||||||
|
dec Json.405;
|
||||||
|
let Json.409 : U64 = 1i64;
|
||||||
|
let Json.408 : {List U8, List U8} = CallByName List.52 Json.282 Json.409;
|
||||||
|
let Json.287 : List U8 = StructAtIndex 1 Json.408;
|
||||||
|
inc Json.287;
|
||||||
|
dec Json.408;
|
||||||
|
let Json.407 : [C {}, C Str] = TagId(1) Json.285;
|
||||||
|
let Json.406 : {List U8, [C {}, C Str]} = Struct {Json.287, Json.407};
|
||||||
|
ret Json.406;
|
||||||
|
else
|
||||||
|
dec Json.405;
|
||||||
|
let Json.412 : {} = Struct {};
|
||||||
|
let Json.411 : [C {}, C Str] = TagId(0) Json.412;
|
||||||
|
let Json.410 : {List U8, [C {}, C Str]} = Struct {Json.282, Json.411};
|
||||||
|
ret Json.410;
|
||||||
|
else
|
||||||
|
dec Json.279;
|
||||||
|
let Json.403 : {} = Struct {};
|
||||||
|
let Json.402 : [C {}, C Str] = TagId(0) Json.403;
|
||||||
|
let Json.401 : {List U8, [C {}, C Str]} = Struct {Json.276, Json.402};
|
||||||
|
ret Json.401;
|
||||||
|
|
||||||
|
procedure Json.41 ():
|
||||||
|
let Json.398 : {} = Struct {};
|
||||||
|
let Json.397 : {} = CallByName Decode.23 Json.398;
|
||||||
|
ret Json.397;
|
||||||
|
|
||||||
|
procedure List.1 (List.94):
|
||||||
|
let List.479 : U64 = CallByName List.6 List.94;
|
||||||
|
let List.480 : U64 = 0i64;
|
||||||
|
let List.478 : Int1 = CallByName Bool.11 List.479 List.480;
|
||||||
|
ret List.478;
|
||||||
|
|
||||||
|
procedure List.2 (List.95, List.96):
|
||||||
|
let List.536 : U64 = CallByName List.6 List.95;
|
||||||
|
let List.532 : Int1 = CallByName Num.22 List.96 List.536;
|
||||||
|
if List.532 then
|
||||||
|
let List.534 : U8 = CallByName List.66 List.95 List.96;
|
||||||
|
let List.533 : [C {}, C U8] = TagId(1) List.534;
|
||||||
|
ret List.533;
|
||||||
|
else
|
||||||
|
let List.531 : {} = Struct {};
|
||||||
|
let List.530 : [C {}, C U8] = TagId(0) List.531;
|
||||||
|
ret List.530;
|
||||||
|
|
||||||
|
procedure List.4 (List.106, List.107):
|
||||||
|
let List.520 : U64 = 1i64;
|
||||||
|
let List.518 : List U8 = CallByName List.70 List.106 List.520;
|
||||||
|
let List.517 : List U8 = CallByName List.71 List.518 List.107;
|
||||||
|
ret List.517;
|
||||||
|
|
||||||
|
procedure List.49 (List.366, List.367):
|
||||||
|
let List.492 : U64 = StructAtIndex 0 List.367;
|
||||||
|
let List.493 : U64 = 0i64;
|
||||||
|
let List.490 : Int1 = CallByName Bool.11 List.492 List.493;
|
||||||
|
if List.490 then
|
||||||
|
dec List.366;
|
||||||
|
let List.491 : List U8 = Array [];
|
||||||
|
ret List.491;
|
||||||
|
else
|
||||||
|
let List.487 : U64 = StructAtIndex 1 List.367;
|
||||||
|
let List.488 : U64 = StructAtIndex 0 List.367;
|
||||||
|
let List.486 : List U8 = CallByName List.72 List.366 List.487 List.488;
|
||||||
|
ret List.486;
|
||||||
|
|
||||||
|
procedure List.52 (List.381, List.382):
|
||||||
|
let List.383 : U64 = CallByName List.6 List.381;
|
||||||
|
joinpoint List.515 List.384:
|
||||||
|
let List.513 : U64 = 0i64;
|
||||||
|
let List.512 : {U64, U64} = Struct {List.384, List.513};
|
||||||
|
inc List.381;
|
||||||
|
let List.385 : List U8 = CallByName List.49 List.381 List.512;
|
||||||
|
let List.511 : U64 = CallByName Num.20 List.383 List.384;
|
||||||
|
let List.510 : {U64, U64} = Struct {List.511, List.384};
|
||||||
|
let List.386 : List U8 = CallByName List.49 List.381 List.510;
|
||||||
|
let List.509 : {List U8, List U8} = Struct {List.385, List.386};
|
||||||
|
ret List.509;
|
||||||
|
in
|
||||||
|
let List.516 : Int1 = CallByName Num.24 List.383 List.382;
|
||||||
|
if List.516 then
|
||||||
|
jump List.515 List.382;
|
||||||
|
else
|
||||||
|
jump List.515 List.383;
|
||||||
|
|
||||||
|
procedure List.6 (#Attr.2):
|
||||||
|
let List.556 : U64 = lowlevel ListLen #Attr.2;
|
||||||
|
ret List.556;
|
||||||
|
|
||||||
|
procedure List.66 (#Attr.2, #Attr.3):
|
||||||
|
let List.535 : U8 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||||
|
ret List.535;
|
||||||
|
|
||||||
|
procedure List.70 (#Attr.2, #Attr.3):
|
||||||
|
let List.521 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||||
|
ret List.521;
|
||||||
|
|
||||||
|
procedure List.71 (#Attr.2, #Attr.3):
|
||||||
|
let List.519 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||||
|
ret List.519;
|
||||||
|
|
||||||
|
procedure List.72 (#Attr.2, #Attr.3, #Attr.4):
|
||||||
|
let List.489 : List U8 = lowlevel ListSublist #Attr.2 #Attr.3 #Attr.4;
|
||||||
|
ret List.489;
|
||||||
|
|
||||||
|
procedure List.9 (List.283):
|
||||||
|
let List.529 : U64 = 0i64;
|
||||||
|
let List.522 : [C {}, C U8] = CallByName List.2 List.283 List.529;
|
||||||
|
let List.526 : U8 = 1i64;
|
||||||
|
let List.527 : U8 = GetTagId List.522;
|
||||||
|
let List.528 : Int1 = lowlevel Eq List.526 List.527;
|
||||||
|
if List.528 then
|
||||||
|
let List.284 : U8 = UnionAtIndex (Id 1) (Index 0) List.522;
|
||||||
|
let List.523 : [C {}, C U8] = TagId(1) List.284;
|
||||||
|
ret List.523;
|
||||||
|
else
|
||||||
|
let List.525 : {} = Struct {};
|
||||||
|
let List.524 : [C {}, C U8] = TagId(0) List.525;
|
||||||
|
ret List.524;
|
||||||
|
|
||||||
|
procedure Num.20 (#Attr.2, #Attr.3):
|
||||||
|
let Num.258 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||||
|
ret Num.258;
|
||||||
|
|
||||||
|
procedure Num.22 (#Attr.2, #Attr.3):
|
||||||
|
let Num.262 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||||
|
ret Num.262;
|
||||||
|
|
||||||
|
procedure Num.24 (#Attr.2, #Attr.3):
|
||||||
|
let Num.261 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||||
|
ret Num.261;
|
||||||
|
|
||||||
|
procedure Str.48 (#Attr.2, #Attr.3, #Attr.4):
|
||||||
|
let Str.274 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||||
|
ret Str.274;
|
||||||
|
|
||||||
|
procedure Str.9 (Str.76):
|
||||||
|
let Str.272 : U64 = 0i64;
|
||||||
|
let Str.273 : U64 = CallByName List.6 Str.76;
|
||||||
|
let Str.77 : {U64, Str, Int1, U8} = CallByName Str.48 Str.76 Str.272 Str.273;
|
||||||
|
let Str.269 : Int1 = StructAtIndex 2 Str.77;
|
||||||
|
if Str.269 then
|
||||||
|
let Str.271 : Str = StructAtIndex 1 Str.77;
|
||||||
|
inc Str.271;
|
||||||
|
dec Str.77;
|
||||||
|
let Str.270 : [C {U64, U8}, C Str] = TagId(1) Str.271;
|
||||||
|
ret Str.270;
|
||||||
|
else
|
||||||
|
let Str.267 : U8 = StructAtIndex 3 Str.77;
|
||||||
|
let Str.268 : U64 = StructAtIndex 0 Str.77;
|
||||||
|
dec Str.77;
|
||||||
|
let Str.266 : {U64, U8} = Struct {Str.268, Str.267};
|
||||||
|
let Str.265 : [C {U64, U8}, C Str] = TagId(0) Str.266;
|
||||||
|
ret Str.265;
|
||||||
|
|
||||||
|
procedure Test.3 ():
|
||||||
|
let Test.0 : List U8 = Array [82i64, 111i64, 99i64];
|
||||||
|
let Test.8 : {} = CallByName Json.2;
|
||||||
|
inc Test.0;
|
||||||
|
let Test.1 : [C [C List U8, C ], C Str] = CallByName Decode.26 Test.0 Test.8;
|
||||||
|
let Test.7 : Str = "Roc";
|
||||||
|
let Test.6 : [C [C List U8, C ], C Str] = TagId(1) Test.7;
|
||||||
|
inc Test.1;
|
||||||
|
let Test.5 : Int1 = CallByName Bool.11 Test.1 Test.6;
|
||||||
|
expect Test.5;
|
||||||
|
let Test.4 : {} = Struct {};
|
||||||
|
ret Test.4;
|
|
@ -0,0 +1,49 @@
|
||||||
|
procedure Bool.11 (#Attr.2, #Attr.3):
|
||||||
|
let Bool.23 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||||
|
ret Bool.23;
|
||||||
|
|
||||||
|
procedure Bool.2 ():
|
||||||
|
let Bool.24 : Int1 = true;
|
||||||
|
ret Bool.24;
|
||||||
|
|
||||||
|
procedure Num.19 (#Attr.2, #Attr.3):
|
||||||
|
let Num.256 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||||
|
ret Num.256;
|
||||||
|
|
||||||
|
procedure Num.21 (#Attr.2, #Attr.3):
|
||||||
|
let Num.257 : U64 = lowlevel NumMul #Attr.2 #Attr.3;
|
||||||
|
ret Num.257;
|
||||||
|
|
||||||
|
procedure Test.0 (Test.8):
|
||||||
|
let Test.23 : Int1 = CallByName Bool.2;
|
||||||
|
if Test.23 then
|
||||||
|
let Test.24 : Int1 = true;
|
||||||
|
ret Test.24;
|
||||||
|
else
|
||||||
|
let Test.22 : Int1 = false;
|
||||||
|
ret Test.22;
|
||||||
|
|
||||||
|
procedure Test.5 (Test.6, Test.2):
|
||||||
|
joinpoint Test.19 Test.18:
|
||||||
|
ret Test.18;
|
||||||
|
in
|
||||||
|
switch Test.2:
|
||||||
|
case 0:
|
||||||
|
let Test.20 : U64 = CallByName Num.19 Test.6 Test.6;
|
||||||
|
jump Test.19 Test.20;
|
||||||
|
|
||||||
|
default:
|
||||||
|
let Test.21 : U64 = CallByName Num.21 Test.6 Test.6;
|
||||||
|
jump Test.19 Test.21;
|
||||||
|
|
||||||
|
|
||||||
|
procedure Test.7 ():
|
||||||
|
let Test.13 : U64 = 3i64;
|
||||||
|
let Test.15 : {} = Struct {};
|
||||||
|
let Test.14 : Int1 = CallByName Test.0 Test.15;
|
||||||
|
let Test.11 : U64 = CallByName Test.5 Test.13 Test.14;
|
||||||
|
let Test.12 : U64 = 9i64;
|
||||||
|
let Test.10 : Int1 = CallByName Bool.11 Test.11 Test.12;
|
||||||
|
expect Test.10;
|
||||||
|
let Test.9 : {} = Struct {};
|
||||||
|
ret Test.9;
|
|
@ -2159,3 +2159,36 @@ fn issue_4705() {
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[mono_test(mode = "test")]
|
||||||
|
fn issue_4749() {
|
||||||
|
indoc!(
|
||||||
|
r###"
|
||||||
|
interface Test exposes [] imports [Json]
|
||||||
|
|
||||||
|
expect
|
||||||
|
input = [82, 111, 99]
|
||||||
|
got = Decode.fromBytes input Json.fromUtf8
|
||||||
|
got == Ok "Roc"
|
||||||
|
"###
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[mono_test(mode = "test", no_check)]
|
||||||
|
fn lambda_set_with_imported_toplevels_issue_4733() {
|
||||||
|
indoc!(
|
||||||
|
r###"
|
||||||
|
interface Test exposes [] imports []
|
||||||
|
|
||||||
|
fn = \{} ->
|
||||||
|
instr : [ Op (U64, U64 -> U64) ]
|
||||||
|
instr = if Bool.true then (Op Num.mul) else (Op Num.add)
|
||||||
|
|
||||||
|
Op op = instr
|
||||||
|
|
||||||
|
\a -> op a a
|
||||||
|
|
||||||
|
expect ((fn {}) 3) == 9
|
||||||
|
"###
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -767,18 +767,23 @@ fn write_content<'a>(
|
||||||
buf.push_str("[[");
|
buf.push_str("[[");
|
||||||
|
|
||||||
let print_symbol = |symbol: &Symbol| {
|
let print_symbol = |symbol: &Symbol| {
|
||||||
|
let ident_str = symbol.as_str(env.interns);
|
||||||
|
let ident_index_str = symbol.ident_id().index().to_string();
|
||||||
|
let disambiguation = if ident_str != ident_index_str {
|
||||||
|
// The pretty name is a named identifier; print the ident as well to avoid
|
||||||
|
// ambguity (in shadows or ability specializations).
|
||||||
|
format!("({ident_index_str})")
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
};
|
||||||
if env.home == symbol.module_id() {
|
if env.home == symbol.module_id() {
|
||||||
format!(
|
format!("{}{}", ident_str, disambiguation,)
|
||||||
"{}({})",
|
|
||||||
symbol.as_str(env.interns),
|
|
||||||
symbol.ident_id().index(),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
"{}.{}({})",
|
"{}.{}{}",
|
||||||
symbol.module_string(env.interns),
|
symbol.module_string(env.interns),
|
||||||
symbol.as_str(env.interns),
|
ident_str,
|
||||||
symbol.ident_id().index(),
|
disambiguation
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -3645,11 +3645,8 @@ impl Alias {
|
||||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||||
pub enum Mismatch {
|
pub enum Mismatch {
|
||||||
TypeMismatch,
|
TypeMismatch,
|
||||||
IfConditionNotBool,
|
|
||||||
InconsistentIfElse,
|
|
||||||
InconsistentWhenBranches,
|
|
||||||
CanonicalizationProblem,
|
|
||||||
TypeNotInRange,
|
TypeNotInRange,
|
||||||
|
DisjointLambdaSets,
|
||||||
DoesNotImplementAbiity(Variable, Symbol),
|
DoesNotImplementAbiity(Variable, Symbol),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -320,7 +320,6 @@ impl<M: MetaCollector> Outcome<M> {
|
||||||
|
|
||||||
pub struct Env<'a> {
|
pub struct Env<'a> {
|
||||||
pub subs: &'a mut Subs,
|
pub subs: &'a mut Subs,
|
||||||
compute_outcome_only: bool,
|
|
||||||
seen_recursion: VecSet<(Variable, Variable)>,
|
seen_recursion: VecSet<(Variable, Variable)>,
|
||||||
fixed_variables: VecSet<Variable>,
|
fixed_variables: VecSet<Variable>,
|
||||||
}
|
}
|
||||||
|
@ -329,21 +328,11 @@ impl<'a> Env<'a> {
|
||||||
pub fn new(subs: &'a mut Subs) -> Self {
|
pub fn new(subs: &'a mut Subs) -> Self {
|
||||||
Self {
|
Self {
|
||||||
subs,
|
subs,
|
||||||
compute_outcome_only: false,
|
|
||||||
seen_recursion: Default::default(),
|
seen_recursion: Default::default(),
|
||||||
fixed_variables: Default::default(),
|
fixed_variables: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Computes a closure in outcome-only mode. Unifications run in outcome-only mode will check
|
|
||||||
// for unifiability, but will not modify type variables or merge them.
|
|
||||||
pub fn with_outcome_only<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
|
|
||||||
self.compute_outcome_only = true;
|
|
||||||
let result = f(self);
|
|
||||||
self.compute_outcome_only = false;
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_recursion_pair(&mut self, var1: Variable, var2: Variable) {
|
fn add_recursion_pair(&mut self, var1: Variable, var2: Variable) {
|
||||||
let pair = (
|
let pair = (
|
||||||
self.subs.get_root_key_without_compacting(var1),
|
self.subs.get_root_key_without_compacting(var1),
|
||||||
|
@ -1331,7 +1320,7 @@ fn separate_union_lambdas<M: MetaCollector>(
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
fields1: UnionLambdas,
|
fields1: UnionLambdas,
|
||||||
fields2: UnionLambdas,
|
fields2: UnionLambdas,
|
||||||
) -> (Outcome<M>, SeparatedUnionLambdas) {
|
) -> Result<(Outcome<M>, SeparatedUnionLambdas), Outcome<M>> {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
fields1.is_sorted_allow_duplicates(env.subs),
|
fields1.is_sorted_allow_duplicates(env.subs),
|
||||||
"not sorted: {:?}",
|
"not sorted: {:?}",
|
||||||
|
@ -1451,20 +1440,56 @@ fn separate_union_lambdas<M: MetaCollector>(
|
||||||
//
|
//
|
||||||
// If they are not unifiable, that means the two lambdas must be
|
// If they are not unifiable, that means the two lambdas must be
|
||||||
// different (since they have different capture sets), and so we don't
|
// different (since they have different capture sets), and so we don't
|
||||||
// want to merge the variables.
|
// want to merge the variables. Instead, we'll treat the lambda sets
|
||||||
let variables_are_unifiable = env.with_outcome_only(|env| {
|
// are disjoint, and keep them as independent lambda in the resulting
|
||||||
unify_pool::<NoCollector>(env, pool, var1, var2, mode)
|
// set.
|
||||||
.mismatches
|
//
|
||||||
.is_empty()
|
// # Nested lambda sets
|
||||||
});
|
//
|
||||||
|
// XREF https://github.com/roc-lang/roc/issues/4712
|
||||||
|
//
|
||||||
|
// We must be careful to ensure that if unifying nested lambda sets
|
||||||
|
// results in disjoint lambdas, that the parent lambda sets are
|
||||||
|
// ultimately treated disjointly as well.
|
||||||
|
// Consider
|
||||||
|
//
|
||||||
|
// v1: {} -[ foo ({} -[ bar Str ]-> {}) ]-> {}
|
||||||
|
// ~ v2: {} -[ foo ({} -[ bar U64 ]-> {}) ]-> {}
|
||||||
|
//
|
||||||
|
// When considering unification of the nested sets
|
||||||
|
//
|
||||||
|
// [ bar Str ]
|
||||||
|
// ~ [ bar U64 ]
|
||||||
|
//
|
||||||
|
// we should not unify these sets, even disjointly, because that would
|
||||||
|
// ultimately lead us to unifying
|
||||||
|
//
|
||||||
|
// v1 ~ v2
|
||||||
|
// => {} -[ foo ({} -[ bar Str, bar U64 ]-> {}) ] -> {}
|
||||||
|
//
|
||||||
|
// which is quite wrong - we do not have a lambda `foo` that captures
|
||||||
|
// either `bar captures: Str` or `bar captures: U64`, we have two
|
||||||
|
// different lambdas `foo` that capture different `bars`. The target
|
||||||
|
// unification is
|
||||||
|
//
|
||||||
|
// v1 ~ v2
|
||||||
|
// => {} -[ foo ({} -[ bar Str ]-> {}),
|
||||||
|
// foo ({} -[ bar U64 ]-> {}) ] -> {}
|
||||||
|
let subs_snapshot = env.subs.snapshot();
|
||||||
|
let pool_snapshot = pool.len();
|
||||||
|
let outcome: Outcome<M> = unify_pool(env, pool, var1, var2, mode);
|
||||||
|
|
||||||
if !variables_are_unifiable {
|
if !outcome.mismatches.is_empty() {
|
||||||
|
// Rolling back will also pull apart any nested lambdas that
|
||||||
|
// were joined into the same set.
|
||||||
|
env.subs.rollback_to(subs_snapshot);
|
||||||
|
pool.truncate(pool_snapshot);
|
||||||
continue 'try_next_right;
|
continue 'try_next_right;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
let outcome = unify_pool(env, pool, var1, var2, mode);
|
let outcome = unify_pool(env, pool, var1, var2, mode);
|
||||||
whole_outcome.union(outcome);
|
whole_outcome.union(outcome);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// All the variables unified, so we can join the left + right.
|
// All the variables unified, so we can join the left + right.
|
||||||
// The variables are unified in left and right slice, so just reuse the left slice.
|
// The variables are unified in left and right slice, so just reuse the left slice.
|
||||||
|
@ -1487,14 +1512,14 @@ fn separate_union_lambdas<M: MetaCollector>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(
|
Ok((
|
||||||
whole_outcome,
|
whole_outcome,
|
||||||
SeparatedUnionLambdas {
|
SeparatedUnionLambdas {
|
||||||
only_in_left,
|
only_in_left,
|
||||||
only_in_right,
|
only_in_right,
|
||||||
joined,
|
joined,
|
||||||
},
|
},
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ULS-SORT-ORDER:
|
/// ULS-SORT-ORDER:
|
||||||
|
@ -1829,7 +1854,10 @@ fn unify_lambda_set_help<M: MetaCollector>(
|
||||||
only_in_right,
|
only_in_right,
|
||||||
joined,
|
joined,
|
||||||
},
|
},
|
||||||
) = separate_union_lambdas(env, pool, ctx.mode, solved1, solved2);
|
) = match separate_union_lambdas(env, pool, ctx.mode, solved1, solved2) {
|
||||||
|
Ok((outcome, separated)) => (outcome, separated),
|
||||||
|
Err(err_outcome) => return err_outcome,
|
||||||
|
};
|
||||||
|
|
||||||
let all_lambdas = joined
|
let all_lambdas = joined
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -3495,7 +3523,6 @@ fn unify_recursion<M: MetaCollector>(
|
||||||
pub fn merge<M: MetaCollector>(env: &mut Env, ctx: &Context, content: Content) -> Outcome<M> {
|
pub fn merge<M: MetaCollector>(env: &mut Env, ctx: &Context, content: Content) -> Outcome<M> {
|
||||||
let mut outcome: Outcome<M> = Outcome::default();
|
let mut outcome: Outcome<M> = Outcome::default();
|
||||||
|
|
||||||
if !env.compute_outcome_only {
|
|
||||||
let rank = ctx.first_desc.rank.min(ctx.second_desc.rank);
|
let rank = ctx.first_desc.rank.min(ctx.second_desc.rank);
|
||||||
let desc = Descriptor {
|
let desc = Descriptor {
|
||||||
content,
|
content,
|
||||||
|
@ -3512,7 +3539,6 @@ pub fn merge<M: MetaCollector>(env: &mut Env, ctx: &Context, content: Content) -
|
||||||
.record_changed_variable(env.subs, ctx.second);
|
.record_changed_variable(env.subs, ctx.second);
|
||||||
|
|
||||||
env.subs.union(ctx.first, ctx.second, desc);
|
env.subs.union(ctx.first, ctx.second, desc);
|
||||||
}
|
|
||||||
|
|
||||||
outcome
|
outcome
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,6 @@ RocNum : [
|
||||||
U128,
|
U128,
|
||||||
F32,
|
F32,
|
||||||
F64,
|
F64,
|
||||||
F128,
|
|
||||||
Dec,
|
Dec,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -571,7 +571,6 @@ struct RocType_RocDict {
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum RocNum {
|
pub enum RocNum {
|
||||||
Dec = 0,
|
Dec = 0,
|
||||||
F128 = 1,
|
|
||||||
F32 = 2,
|
F32 = 2,
|
||||||
F64 = 3,
|
F64 = 3,
|
||||||
I128 = 4,
|
I128 = 4,
|
||||||
|
@ -590,7 +589,6 @@ impl core::fmt::Debug for RocNum {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Dec => f.write_str("RocNum::Dec"),
|
Self::Dec => f.write_str("RocNum::Dec"),
|
||||||
Self::F128 => f.write_str("RocNum::F128"),
|
|
||||||
Self::F32 => f.write_str("RocNum::F32"),
|
Self::F32 => f.write_str("RocNum::F32"),
|
||||||
Self::F64 => f.write_str("RocNum::F64"),
|
Self::F64 => f.write_str("RocNum::F64"),
|
||||||
Self::I128 => f.write_str("RocNum::I128"),
|
Self::I128 => f.write_str("RocNum::I128"),
|
||||||
|
|
|
@ -1737,7 +1737,6 @@ fn type_name(id: TypeId, types: &Types) -> String {
|
||||||
RocType::Num(RocNum::I128) => "roc_std::I128".to_string(),
|
RocType::Num(RocNum::I128) => "roc_std::I128".to_string(),
|
||||||
RocType::Num(RocNum::F32) => "f32".to_string(),
|
RocType::Num(RocNum::F32) => "f32".to_string(),
|
||||||
RocType::Num(RocNum::F64) => "f64".to_string(),
|
RocType::Num(RocNum::F64) => "f64".to_string(),
|
||||||
RocType::Num(RocNum::F128) => "roc_std::F128".to_string(),
|
|
||||||
RocType::Num(RocNum::Dec) => "roc_std::RocDec".to_string(),
|
RocType::Num(RocNum::Dec) => "roc_std::RocDec".to_string(),
|
||||||
RocType::RocDict(key_id, val_id) => format!(
|
RocType::RocDict(key_id, val_id) => format!(
|
||||||
"roc_std::RocDict<{}, {}>",
|
"roc_std::RocDict<{}, {}>",
|
||||||
|
@ -2433,7 +2432,7 @@ fn has_float_help(roc_type: &RocType, types: &Types, do_not_recurse: &[TypeId])
|
||||||
use RocNum::*;
|
use RocNum::*;
|
||||||
|
|
||||||
match num {
|
match num {
|
||||||
F32 | F64 | F128 => true,
|
F32 | F64 => true,
|
||||||
I8 | U8 | I16 | U16 | I32 | U32 | I64 | U64 | I128 | U128 | Dec => false,
|
I8 | U8 | I16 | U16 | I32 | U32 | I64 | U64 | I128 | U128 | Dec => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -544,7 +544,6 @@ pub enum RocNum {
|
||||||
U128,
|
U128,
|
||||||
F32,
|
F32,
|
||||||
F64,
|
F64,
|
||||||
F128,
|
|
||||||
Dec,
|
Dec,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,7 +565,6 @@ impl RocNum {
|
||||||
RocNum::U128 => size_of::<roc_std::U128>(),
|
RocNum::U128 => size_of::<roc_std::U128>(),
|
||||||
RocNum::F32 => size_of::<f32>(),
|
RocNum::F32 => size_of::<f32>(),
|
||||||
RocNum::F64 => size_of::<f64>(),
|
RocNum::F64 => size_of::<f64>(),
|
||||||
RocNum::F128 => todo!(),
|
|
||||||
RocNum::Dec => size_of::<roc_std::RocDec>(),
|
RocNum::Dec => size_of::<roc_std::RocDec>(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1083,11 +1081,6 @@ fn add_builtin_type<'a>(
|
||||||
RocType::Num(RocNum::F64),
|
RocType::Num(RocNum::F64),
|
||||||
layout,
|
layout,
|
||||||
),
|
),
|
||||||
F128 => types.add_anonymous(
|
|
||||||
&env.layout_cache.interner,
|
|
||||||
RocType::Num(RocNum::F128),
|
|
||||||
layout,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
(Builtin::Decimal, _) => types.add_anonymous(
|
(Builtin::Decimal, _) => types.add_anonymous(
|
||||||
&env.layout_cache.interner,
|
&env.layout_cache.interner,
|
||||||
|
|
|
@ -172,7 +172,7 @@ fn unroll_newtypes_and_aliases<'a, 'env>(
|
||||||
var = field.into_inner();
|
var = field.into_inner();
|
||||||
}
|
}
|
||||||
Content::Alias(name, _, real_var, kind) => {
|
Content::Alias(name, _, real_var, kind) => {
|
||||||
if *name == Symbol::BOOL_BOOL {
|
if *name == Symbol::BOOL_BOOL || name.module_id() == ModuleId::NUM {
|
||||||
return (newtype_containers, alias_content, var);
|
return (newtype_containers, alias_content, var);
|
||||||
}
|
}
|
||||||
// We need to pass through aliases too, because their underlying types may have
|
// We need to pass through aliases too, because their underlying types may have
|
||||||
|
@ -185,7 +185,7 @@ fn unroll_newtypes_and_aliases<'a, 'env>(
|
||||||
//
|
//
|
||||||
// At the end of the day what we should show to the user is the alias content, not
|
// 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.
|
// what's inside, so keep that around too.
|
||||||
if *kind == AliasKind::Opaque && name.module_id() != ModuleId::NUM {
|
if *kind == AliasKind::Opaque {
|
||||||
newtype_containers.push(NewtypeKind::Opaque(*name));
|
newtype_containers.push(NewtypeKind::Opaque(*name));
|
||||||
}
|
}
|
||||||
alias_content = Some(content);
|
alias_content = Some(content);
|
||||||
|
@ -361,10 +361,11 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
||||||
use Content::*;
|
use Content::*;
|
||||||
use IntWidth::*;
|
use IntWidth::*;
|
||||||
|
|
||||||
match (alias_content, int_width) {
|
match (env.subs.get_content_without_compacting(raw_var), int_width) {
|
||||||
(Some(Alias(Symbol::NUM_UNSIGNED8, ..)), U8) => num_helper!(u8),
|
(Alias(Symbol::NUM_UNSIGNED8 | Symbol::NUM_U8, ..), U8) => num_helper!(u8),
|
||||||
(_, U8) => {
|
(_, U8) => {
|
||||||
// This is not a number, it's a tag union or something else
|
// This is not a number, it's a tag union or something else
|
||||||
|
dbg!(&alias_content);
|
||||||
app.call_function(main_fn_name, |_mem: &A::Memory, num: u8| {
|
app.call_function(main_fn_name, |_mem: &A::Memory, num: u8| {
|
||||||
byte_to_ast(env, num, env.subs.get_content_without_compacting(raw_var))
|
byte_to_ast(env, num, env.subs.get_content_without_compacting(raw_var))
|
||||||
})
|
})
|
||||||
|
@ -387,7 +388,6 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
||||||
match float_width {
|
match float_width {
|
||||||
F32 => num_helper!(f32),
|
F32 => num_helper!(f32),
|
||||||
F64 => num_helper!(f64),
|
F64 => num_helper!(f64),
|
||||||
F128 => todo!("F128 not implemented"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::Decimal) => num_helper!(RocDec),
|
Layout::Builtin(Builtin::Decimal) => num_helper!(RocDec),
|
||||||
|
@ -565,7 +565,13 @@ fn addr_to_ast<'a, M: ReplAppMemory>(
|
||||||
use IntWidth::*;
|
use IntWidth::*;
|
||||||
|
|
||||||
match int_width {
|
match int_width {
|
||||||
U8 => helper!(deref_u8, u8),
|
U8 => {
|
||||||
|
if matches!(raw_content, Content::Alias(name, ..) if name.module_id() == ModuleId::NUM) {
|
||||||
|
helper!(deref_u8, u8)
|
||||||
|
} else {
|
||||||
|
byte_to_ast(env, mem.deref_u8(addr), raw_content)
|
||||||
|
}
|
||||||
|
},
|
||||||
U16 => helper!(deref_u16, u16),
|
U16 => helper!(deref_u16, u16),
|
||||||
U32 => helper!(deref_u32, u32),
|
U32 => helper!(deref_u32, u32),
|
||||||
U64 => helper!(deref_u64, u64),
|
U64 => helper!(deref_u64, u64),
|
||||||
|
@ -583,7 +589,6 @@ fn addr_to_ast<'a, M: ReplAppMemory>(
|
||||||
match float_width {
|
match float_width {
|
||||||
F32 => helper!(deref_f32, f32),
|
F32 => helper!(deref_f32, f32),
|
||||||
F64 => helper!(deref_f64, f64),
|
F64 => helper!(deref_f64, f64),
|
||||||
F128 => todo!("F128 not implemented"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(_, Layout::Builtin(Builtin::List(elem_layout))) => {
|
(_, Layout::Builtin(Builtin::List(elem_layout))) => {
|
||||||
|
|
|
@ -32,9 +32,10 @@ pub fn get_values<'a>(
|
||||||
layout_interner: &Arc<GlobalInterner<'a, Layout<'a>>>,
|
layout_interner: &Arc<GlobalInterner<'a, Layout<'a>>>,
|
||||||
start: *const u8,
|
start: *const u8,
|
||||||
start_offset: usize,
|
start_offset: usize,
|
||||||
variables: &[Variable],
|
number_of_lookups: usize,
|
||||||
) -> (usize, Vec<Expr<'a>>) {
|
) -> (usize, Vec<Expr<'a>>, Vec<Variable>) {
|
||||||
let mut result = Vec::with_capacity(variables.len());
|
let mut result = Vec::with_capacity(number_of_lookups);
|
||||||
|
let mut result_vars = Vec::with_capacity(number_of_lookups);
|
||||||
|
|
||||||
let memory = ExpectMemory { start };
|
let memory = ExpectMemory { start };
|
||||||
|
|
||||||
|
@ -45,13 +46,20 @@ pub fn get_values<'a>(
|
||||||
|
|
||||||
let app = arena.alloc(app);
|
let app = arena.alloc(app);
|
||||||
|
|
||||||
for (i, variable) in variables.iter().enumerate() {
|
for i in 0..number_of_lookups {
|
||||||
let start = app.memory.deref_usize(start_offset + i * 8);
|
let size_of_lookup_header = 8 /* pointer to value */ + 4 /* type variable */;
|
||||||
|
|
||||||
|
let start = app
|
||||||
|
.memory
|
||||||
|
.deref_usize(start_offset + i * size_of_lookup_header);
|
||||||
|
let variable = app.memory.deref_u32(
|
||||||
|
start_offset + i * size_of_lookup_header + 8, /* skip the pointer */
|
||||||
|
);
|
||||||
|
let variable = unsafe { Variable::from_index(variable) };
|
||||||
|
|
||||||
app.offset = start;
|
app.offset = start;
|
||||||
|
|
||||||
let expr = {
|
let expr = {
|
||||||
let variable = *variable;
|
|
||||||
|
|
||||||
// TODO: pass layout_cache to jit_to_ast directly
|
// TODO: pass layout_cache to jit_to_ast directly
|
||||||
let mut layout_cache = LayoutCache::new(layout_interner.fork(), target_info);
|
let mut layout_cache = LayoutCache::new(layout_interner.fork(), target_info);
|
||||||
let layout = layout_cache.from_var(arena, variable, subs).unwrap();
|
let layout = layout_cache.from_var(arena, variable, subs).unwrap();
|
||||||
|
@ -76,9 +84,10 @@ pub fn get_values<'a>(
|
||||||
};
|
};
|
||||||
|
|
||||||
result.push(expr);
|
result.push(expr);
|
||||||
|
result_vars.push(variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
(app.offset, result)
|
(app.offset, result, result_vars)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
|
|
|
@ -25,7 +25,7 @@ use roc_mono::{ir::OptLevel, layout::Layout};
|
||||||
use roc_region::all::Region;
|
use roc_region::all::Region;
|
||||||
use roc_reporting::{error::expect::Renderer, report::RenderTarget};
|
use roc_reporting::{error::expect::Renderer, report::RenderTarget};
|
||||||
use roc_target::TargetInfo;
|
use roc_target::TargetInfo;
|
||||||
use roc_types::subs::{Subs, Variable};
|
use roc_types::subs::Subs;
|
||||||
use target_lexicon::Triple;
|
use target_lexicon::Triple;
|
||||||
|
|
||||||
pub struct ExpectMemory<'a> {
|
pub struct ExpectMemory<'a> {
|
||||||
|
@ -471,7 +471,7 @@ pub fn render_dbgs_in_memory<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn split_expect_lookups(subs: &Subs, lookups: &[ExpectLookup]) -> (Vec<Symbol>, Vec<Variable>) {
|
fn split_expect_lookups(subs: &Subs, lookups: &[ExpectLookup]) -> Vec<Symbol> {
|
||||||
lookups
|
lookups
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(
|
.filter_map(
|
||||||
|
@ -485,11 +485,11 @@ fn split_expect_lookups(subs: &Subs, lookups: &[ExpectLookup]) -> (Vec<Symbol>,
|
||||||
if subs.is_function(*var) {
|
if subs.is_function(*var) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some((*symbol, *var))
|
Some(*symbol)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unzip()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
@ -523,15 +523,7 @@ fn render_dbg_failure<'a>(
|
||||||
|
|
||||||
let subs = arena.alloc(&mut data.subs);
|
let subs = arena.alloc(&mut data.subs);
|
||||||
|
|
||||||
let current = ExpectLookup {
|
let (offset, expressions, _variables) = crate::get_values(
|
||||||
symbol: current.symbol,
|
|
||||||
var: current.var,
|
|
||||||
ability_info: current.ability_info,
|
|
||||||
};
|
|
||||||
|
|
||||||
let (_symbols, variables) = split_expect_lookups(subs, &[current]);
|
|
||||||
|
|
||||||
let (offset, expressions) = crate::get_values(
|
|
||||||
target_info,
|
target_info,
|
||||||
arena,
|
arena,
|
||||||
subs,
|
subs,
|
||||||
|
@ -539,7 +531,7 @@ fn render_dbg_failure<'a>(
|
||||||
layout_interner,
|
layout_interner,
|
||||||
start,
|
start,
|
||||||
frame.start_offset,
|
frame.start_offset,
|
||||||
&variables,
|
1,
|
||||||
);
|
);
|
||||||
|
|
||||||
renderer.render_dbg(writer, &expressions, expect_region, failure_region)?;
|
renderer.render_dbg(writer, &expressions, expect_region, failure_region)?;
|
||||||
|
@ -574,24 +566,23 @@ fn render_expect_failure<'a>(
|
||||||
None => panic!("region {failure_region:?} not in list of expects"),
|
None => panic!("region {failure_region:?} not in list of expects"),
|
||||||
Some(current) => current,
|
Some(current) => current,
|
||||||
};
|
};
|
||||||
let subs = arena.alloc(&mut data.subs);
|
|
||||||
|
|
||||||
let (symbols, variables) = split_expect_lookups(subs, current);
|
let symbols = split_expect_lookups(&data.subs, current);
|
||||||
|
|
||||||
let (offset, expressions) = crate::get_values(
|
let (offset, expressions, variables) = crate::get_values(
|
||||||
target_info,
|
target_info,
|
||||||
arena,
|
arena,
|
||||||
subs,
|
&data.subs,
|
||||||
interns,
|
interns,
|
||||||
layout_interner,
|
layout_interner,
|
||||||
start,
|
start,
|
||||||
frame.start_offset,
|
frame.start_offset,
|
||||||
&variables,
|
symbols.len(),
|
||||||
);
|
);
|
||||||
|
|
||||||
renderer.render_failure(
|
renderer.render_failure(
|
||||||
writer,
|
writer,
|
||||||
subs,
|
&mut data.subs,
|
||||||
&symbols,
|
&symbols,
|
||||||
&variables,
|
&variables,
|
||||||
&expressions,
|
&expressions,
|
||||||
|
|
|
@ -1256,3 +1256,15 @@ fn newtype_by_void_is_wrapped() {
|
||||||
r#"Ok 43 : Result (Num *) err"#,
|
r#"Ok 43 : Result (Num *) err"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn enum_tag_union_in_list() {
|
||||||
|
expect_success(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
[E, F, G, H]
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
r#"[E, F, G, H] : List [E, F, G, H]"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -105,7 +105,8 @@
|
||||||
debugir
|
debugir
|
||||||
rust
|
rust
|
||||||
rust-bindgen
|
rust-bindgen
|
||||||
cargo-criterion
|
cargo-criterion # for benchmarks
|
||||||
|
simple-http-server # to view roc website when trying out edits
|
||||||
]);
|
]);
|
||||||
in {
|
in {
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,9 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pattern": "https://web.eecs.umich.edu"
|
"pattern": "https://web.eecs.umich.edu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pattern": "http://0.0.0.0:8000"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
# www.roc-lang.org
|
# www.roc-lang.org
|
||||||
|
|
||||||
## How to update site
|
To view the website after you've made a change, execute:
|
||||||
|
```bash
|
||||||
- create a new branch, for example `update-www` based on `www`
|
./www/build.sh
|
||||||
- pull `main` into `update-www`
|
cd www/build
|
||||||
- update for example the file `www/public/index.html`
|
simple-http-server # If you're using the nix flake simple-http-server will already be installed. Withouth nix you can install it with `cargo install simple-http-server`.
|
||||||
- do a PR against `www`
|
```
|
||||||
- check deploy preview
|
Open http://0.0.0.0:8000 in your browser.
|
||||||
- review and merge
|
|
||||||
|
|
|
@ -1195,6 +1195,16 @@ expect pluralize <span class="str">"cactus"</span> <span class="str">"cacti"</sp
|
||||||
</samp>
|
</samp>
|
||||||
<p>If you put this in a file named <code>main.roc</code> and run <code>roc test</code>, Roc will execute the two <code>expect</code>
|
<p>If you put this in a file named <code>main.roc</code> and run <code>roc test</code>, Roc will execute the two <code>expect</code>
|
||||||
expressions (that is, the two <code>pluralize</code> calls) and report any that returned <code>false</code>.</p>
|
expressions (that is, the two <code>pluralize</code> calls) and report any that returned <code>false</code>.</p>
|
||||||
|
|
||||||
|
<p>If a test fails, it will not show the actual value that differs from the expected value.
|
||||||
|
To show the actual value, you can write the expect like this:</p>
|
||||||
|
|
||||||
|
<samp>expect
|
||||||
|
funcOut <span class="op">=</span> pluralize <span class="str">"cactus"</span> <span class="str">"cacti"</span> 1
|
||||||
|
|
||||||
|
funcOut <span class="op">==</span> <span class="str">"2 cactus"</span>
|
||||||
|
</samp>
|
||||||
|
|
||||||
<h3 id="inline-expects"><a href="#inline-expects">Inline Expectations</a></h3>
|
<h3 id="inline-expects"><a href="#inline-expects">Inline Expectations</a></h3>
|
||||||
<p>For example:</p>
|
<p>For example:</p>
|
||||||
<samp> <span class="kw">if</span> count <span class="op">==</span> <span class="number">1</span> then
|
<samp> <span class="kw">if</span> count <span class="op">==</span> <span class="number">1</span> then
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue