mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Merge remote-tracking branch 'origin/main' into repl
This commit is contained in:
commit
c03dc17ab4
197 changed files with 5171 additions and 2946 deletions
|
@ -4,21 +4,15 @@ use roc_builtins::bitcode;
|
|||
use roc_error_macros::internal_error;
|
||||
use roc_mono::ir::OptLevel;
|
||||
use roc_utils::get_lib_path;
|
||||
use roc_utils::{cargo, clang, zig};
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{self, Child, Command, Output};
|
||||
use std::process::{self, Child, Command};
|
||||
use target_lexicon::{Architecture, OperatingSystem, Triple};
|
||||
use wasi_libc_sys::{WASI_COMPILER_RT_PATH, WASI_LIBC_PATH};
|
||||
|
||||
fn zig_executable() -> String {
|
||||
match std::env::var("ROC_ZIG") {
|
||||
Ok(path) => path,
|
||||
Err(_) => "zig".into(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum LinkType {
|
||||
// These numbers correspond to the --lib and --no-link flags
|
||||
|
@ -113,9 +107,9 @@ pub fn build_zig_host_native(
|
|||
target: &str,
|
||||
opt_level: OptLevel,
|
||||
shared_lib_path: Option<&Path>,
|
||||
) -> Output {
|
||||
let mut command = Command::new(&zig_executable());
|
||||
command
|
||||
) -> Command {
|
||||
let mut zig_cmd = zig();
|
||||
zig_cmd
|
||||
.env_clear()
|
||||
.env("PATH", env_path)
|
||||
.env("HOME", env_home);
|
||||
|
@ -130,7 +124,7 @@ pub fn build_zig_host_native(
|
|||
bitcode::get_builtins_host_obj_path()
|
||||
};
|
||||
|
||||
command.args(&[
|
||||
zig_cmd.args([
|
||||
"build-exe",
|
||||
"-fPIE",
|
||||
"-rdynamic", // make sure roc_alloc and friends are exposed
|
||||
|
@ -138,12 +132,12 @@ pub fn build_zig_host_native(
|
|||
&builtins_obj,
|
||||
]);
|
||||
} else {
|
||||
command.args(&["build-obj", "-fPIC"]);
|
||||
zig_cmd.args(["build-obj", "-fPIC"]);
|
||||
}
|
||||
|
||||
command.args(&[
|
||||
zig_cmd.args([
|
||||
zig_host_src,
|
||||
emit_bin,
|
||||
&format!("-femit-bin={}", emit_bin),
|
||||
"--pkg-begin",
|
||||
"str",
|
||||
zig_str_path,
|
||||
|
@ -160,7 +154,7 @@ pub fn build_zig_host_native(
|
|||
// when we use zig 0.9. It looks like zig 0.10 is going to fix
|
||||
// this problem for us, so this is a temporary workaround
|
||||
if !target.contains("windows") {
|
||||
command.args(&[
|
||||
zig_cmd.args([
|
||||
// include the zig runtime
|
||||
"-fcompiler-rt",
|
||||
]);
|
||||
|
@ -168,16 +162,16 @@ pub fn build_zig_host_native(
|
|||
|
||||
// valgrind does not yet support avx512 instructions, see #1963.
|
||||
if env::var("NO_AVX512").is_ok() {
|
||||
command.args(&["-mcpu", "x86_64"]);
|
||||
zig_cmd.args(["-mcpu", "x86_64"]);
|
||||
}
|
||||
|
||||
if matches!(opt_level, OptLevel::Optimize) {
|
||||
command.args(&["-O", "ReleaseSafe"]);
|
||||
zig_cmd.args(["-O", "ReleaseSafe"]);
|
||||
} else if matches!(opt_level, OptLevel::Size) {
|
||||
command.args(&["-O", "ReleaseSmall"]);
|
||||
zig_cmd.args(["-O", "ReleaseSmall"]);
|
||||
}
|
||||
|
||||
command.output().unwrap()
|
||||
zig_cmd
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
|
@ -191,27 +185,27 @@ pub fn build_zig_host_native(
|
|||
target: &str,
|
||||
opt_level: OptLevel,
|
||||
shared_lib_path: Option<&Path>,
|
||||
) -> Output {
|
||||
let mut command = Command::new(&zig_executable());
|
||||
command
|
||||
) -> Command {
|
||||
let mut zig_cmd = zig();
|
||||
zig_cmd
|
||||
.env_clear()
|
||||
.env("PATH", env_path)
|
||||
.env("HOME", env_home);
|
||||
|
||||
if let Some(shared_lib_path) = shared_lib_path {
|
||||
command.args(&[
|
||||
zig_cmd.args(&[
|
||||
"build-exe",
|
||||
// "-fPIE", PIE seems to fail on windows
|
||||
shared_lib_path.to_str().unwrap(),
|
||||
&bitcode::get_builtins_windows_obj_path(),
|
||||
]);
|
||||
} else {
|
||||
command.args(&["build-obj", "-fPIC"]);
|
||||
zig_cmd.args(&["build-obj", "-fPIC"]);
|
||||
}
|
||||
|
||||
command.args(&[
|
||||
zig_cmd.args(&[
|
||||
zig_host_src,
|
||||
emit_bin,
|
||||
&format!("-femit-bin={}", emit_bin),
|
||||
"--pkg-begin",
|
||||
"str",
|
||||
zig_str_path,
|
||||
|
@ -227,12 +221,12 @@ pub fn build_zig_host_native(
|
|||
]);
|
||||
|
||||
if matches!(opt_level, OptLevel::Optimize) {
|
||||
command.args(&["-O", "ReleaseSafe"]);
|
||||
zig_cmd.args(&["-O", "ReleaseSafe"]);
|
||||
} else if matches!(opt_level, OptLevel::Size) {
|
||||
command.args(&["-O", "ReleaseSmall"]);
|
||||
zig_cmd.args(&["-O", "ReleaseSmall"]);
|
||||
}
|
||||
|
||||
command.output().unwrap()
|
||||
zig_cmd
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
|
@ -247,14 +241,11 @@ pub fn build_zig_host_native(
|
|||
opt_level: OptLevel,
|
||||
shared_lib_path: Option<&Path>,
|
||||
// For compatibility with the non-macOS def above. Keep these in sync.
|
||||
) -> Output {
|
||||
) -> Command {
|
||||
use serde_json::Value;
|
||||
|
||||
// Run `zig env` to find the location of zig's std/ directory
|
||||
let zig_env_output = Command::new(&zig_executable())
|
||||
.args(&["env"])
|
||||
.output()
|
||||
.unwrap();
|
||||
let zig_env_output = zig().args(&["env"]).output().unwrap();
|
||||
|
||||
let zig_env_json = if zig_env_output.status.success() {
|
||||
std::str::from_utf8(&zig_env_output.stdout).unwrap_or_else(|utf8_err| {
|
||||
|
@ -291,24 +282,24 @@ pub fn build_zig_host_native(
|
|||
zig_compiler_rt_path.push("special");
|
||||
zig_compiler_rt_path.push("compiler_rt.zig");
|
||||
|
||||
let mut command = Command::new(&zig_executable());
|
||||
command
|
||||
let mut zig_cmd = zig();
|
||||
zig_cmd
|
||||
.env_clear()
|
||||
.env("PATH", &env_path)
|
||||
.env("HOME", &env_home);
|
||||
if let Some(shared_lib_path) = shared_lib_path {
|
||||
command.args(&[
|
||||
zig_cmd.args(&[
|
||||
"build-exe",
|
||||
"-fPIE",
|
||||
shared_lib_path.to_str().unwrap(),
|
||||
&bitcode::get_builtins_host_obj_path(),
|
||||
]);
|
||||
} else {
|
||||
command.args(&["build-obj", "-fPIC"]);
|
||||
zig_cmd.args(&["build-obj", "-fPIC"]);
|
||||
}
|
||||
command.args(&[
|
||||
zig_cmd.args(&[
|
||||
zig_host_src,
|
||||
emit_bin,
|
||||
&format!("-femit-bin={}", emit_bin),
|
||||
"--pkg-begin",
|
||||
"str",
|
||||
zig_str_path,
|
||||
|
@ -323,11 +314,12 @@ pub fn build_zig_host_native(
|
|||
"c",
|
||||
]);
|
||||
if matches!(opt_level, OptLevel::Optimize) {
|
||||
command.args(&["-O", "ReleaseSafe"]);
|
||||
zig_cmd.args(&["-O", "ReleaseSafe"]);
|
||||
} else if matches!(opt_level, OptLevel::Size) {
|
||||
command.args(&["-O", "ReleaseSmall"]);
|
||||
zig_cmd.args(&["-O", "ReleaseSmall"]);
|
||||
}
|
||||
command.output().unwrap()
|
||||
|
||||
zig_cmd
|
||||
}
|
||||
|
||||
pub fn build_zig_host_wasm32(
|
||||
|
@ -338,7 +330,7 @@ pub fn build_zig_host_wasm32(
|
|||
zig_str_path: &str,
|
||||
opt_level: OptLevel,
|
||||
shared_lib_path: Option<&Path>,
|
||||
) -> Output {
|
||||
) -> Command {
|
||||
if shared_lib_path.is_some() {
|
||||
unimplemented!("Linking a shared library to wasm not yet implemented");
|
||||
}
|
||||
|
@ -358,7 +350,7 @@ pub fn build_zig_host_wasm32(
|
|||
// we'd like to compile with `-target wasm32-wasi` but that is blocked on
|
||||
//
|
||||
// https://github.com/ziglang/zig/issues/9414
|
||||
let mut command = Command::new(&zig_executable());
|
||||
let mut zig_cmd = zig();
|
||||
let args = &[
|
||||
"build-obj",
|
||||
zig_host_src,
|
||||
|
@ -379,18 +371,19 @@ pub fn build_zig_host_wasm32(
|
|||
"--strip",
|
||||
];
|
||||
|
||||
command
|
||||
zig_cmd
|
||||
.env_clear()
|
||||
.env("PATH", env_path)
|
||||
.env("HOME", env_home)
|
||||
.args(args);
|
||||
|
||||
if matches!(opt_level, OptLevel::Optimize) {
|
||||
command.args(&["-O", "ReleaseSafe"]);
|
||||
zig_cmd.args(["-O", "ReleaseSafe"]);
|
||||
} else if matches!(opt_level, OptLevel::Size) {
|
||||
command.args(&["-O", "ReleaseSmall"]);
|
||||
zig_cmd.args(["-O", "ReleaseSmall"]);
|
||||
}
|
||||
command.output().unwrap()
|
||||
|
||||
zig_cmd
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
@ -403,15 +396,15 @@ pub fn build_c_host_native(
|
|||
sources: &[&str],
|
||||
opt_level: OptLevel,
|
||||
shared_lib_path: Option<&Path>,
|
||||
) -> Output {
|
||||
let mut command = Command::new("clang");
|
||||
command
|
||||
) -> Command {
|
||||
let mut clang_cmd = clang();
|
||||
clang_cmd
|
||||
.env_clear()
|
||||
.env("PATH", &env_path)
|
||||
.env("CPATH", &env_cpath)
|
||||
.env("HOME", &env_home)
|
||||
.env("PATH", env_path)
|
||||
.env("CPATH", env_cpath)
|
||||
.env("HOME", env_home)
|
||||
.args(sources)
|
||||
.args(&["-o", dest]);
|
||||
.args(["-o", dest]);
|
||||
if let Some(shared_lib_path) = shared_lib_path {
|
||||
match target.operating_system {
|
||||
OperatingSystem::Windows => {
|
||||
|
@ -432,7 +425,7 @@ pub fn build_c_host_native(
|
|||
);
|
||||
}
|
||||
_ => {
|
||||
command.args(&[
|
||||
clang_cmd.args([
|
||||
shared_lib_path.to_str().unwrap(),
|
||||
// This line is commented out because
|
||||
// @bhansconnect: With the addition of Str.graphemes, always
|
||||
|
@ -451,14 +444,15 @@ pub fn build_c_host_native(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
command.args(&["-fPIC", "-c"]);
|
||||
clang_cmd.args(["-fPIC", "-c"]);
|
||||
}
|
||||
if matches!(opt_level, OptLevel::Optimize) {
|
||||
command.arg("-O3");
|
||||
clang_cmd.arg("-O3");
|
||||
} else if matches!(opt_level, OptLevel::Size) {
|
||||
command.arg("-Os");
|
||||
clang_cmd.arg("-Os");
|
||||
}
|
||||
command.output().unwrap()
|
||||
|
||||
clang_cmd
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
@ -471,7 +465,7 @@ pub fn build_swift_host_native(
|
|||
shared_lib_path: Option<&Path>,
|
||||
objc_header_path: Option<&str>,
|
||||
arch: Architecture,
|
||||
) -> Output {
|
||||
) -> Command {
|
||||
if shared_lib_path.is_some() {
|
||||
unimplemented!("Linking a shared library to Swift not yet implemented");
|
||||
}
|
||||
|
@ -479,8 +473,8 @@ pub fn build_swift_host_native(
|
|||
let mut command = Command::new("arch");
|
||||
command
|
||||
.env_clear()
|
||||
.env("PATH", &env_path)
|
||||
.env("HOME", &env_home);
|
||||
.env("PATH", env_path)
|
||||
.env("HOME", env_home);
|
||||
|
||||
match arch {
|
||||
Architecture::Aarch64(_) => command.arg("-arm64"),
|
||||
|
@ -493,10 +487,10 @@ pub fn build_swift_host_native(
|
|||
.args(sources)
|
||||
.arg("-emit-object")
|
||||
.arg("-parse-as-library")
|
||||
.args(&["-o", dest]);
|
||||
.args(["-o", dest]);
|
||||
|
||||
if let Some(objc_header) = objc_header_path {
|
||||
command.args(&["-import-objc-header", objc_header]);
|
||||
command.args(["-import-objc-header", objc_header]);
|
||||
}
|
||||
|
||||
if matches!(opt_level, OptLevel::Optimize) {
|
||||
|
@ -505,7 +499,7 @@ pub fn build_swift_host_native(
|
|||
command.arg("-Osize");
|
||||
}
|
||||
|
||||
command.output().unwrap()
|
||||
command
|
||||
}
|
||||
|
||||
pub fn rebuild_host(
|
||||
|
@ -567,7 +561,7 @@ pub fn rebuild_host(
|
|||
&zig_str_path
|
||||
);
|
||||
|
||||
let output = match target.architecture {
|
||||
let zig_cmd = match target.architecture {
|
||||
Architecture::Wasm32 => {
|
||||
let emit_bin = if matches!(opt_level, OptLevel::Development) {
|
||||
format!("-femit-bin={}", host_dest.to_str().unwrap())
|
||||
|
@ -585,8 +579,6 @@ pub fn rebuild_host(
|
|||
)
|
||||
}
|
||||
Architecture::X86_64 => {
|
||||
let emit_bin = format!("-femit-bin={}", host_dest.to_str().unwrap());
|
||||
|
||||
let target = match target.operating_system {
|
||||
OperatingSystem::Windows => "x86_64-windows-gnu",
|
||||
_ => "native",
|
||||
|
@ -595,7 +587,7 @@ pub fn rebuild_host(
|
|||
build_zig_host_native(
|
||||
&env_path,
|
||||
&env_home,
|
||||
&emit_bin,
|
||||
host_dest.to_str().unwrap(),
|
||||
zig_host_src.to_str().unwrap(),
|
||||
zig_str_path.to_str().unwrap(),
|
||||
target,
|
||||
|
@ -603,37 +595,31 @@ pub fn rebuild_host(
|
|||
shared_lib_path,
|
||||
)
|
||||
}
|
||||
Architecture::X86_32(_) => {
|
||||
let emit_bin = format!("-femit-bin={}", host_dest.to_str().unwrap());
|
||||
build_zig_host_native(
|
||||
&env_path,
|
||||
&env_home,
|
||||
&emit_bin,
|
||||
zig_host_src.to_str().unwrap(),
|
||||
zig_str_path.to_str().unwrap(),
|
||||
"i386-linux-musl",
|
||||
opt_level,
|
||||
shared_lib_path,
|
||||
)
|
||||
}
|
||||
Architecture::X86_32(_) => build_zig_host_native(
|
||||
&env_path,
|
||||
&env_home,
|
||||
host_dest.to_str().unwrap(),
|
||||
zig_host_src.to_str().unwrap(),
|
||||
zig_str_path.to_str().unwrap(),
|
||||
"i386-linux-musl",
|
||||
opt_level,
|
||||
shared_lib_path,
|
||||
),
|
||||
|
||||
Architecture::Aarch64(_) => {
|
||||
let emit_bin = format!("-femit-bin={}", host_dest.to_str().unwrap());
|
||||
build_zig_host_native(
|
||||
&env_path,
|
||||
&env_home,
|
||||
&emit_bin,
|
||||
zig_host_src.to_str().unwrap(),
|
||||
zig_str_path.to_str().unwrap(),
|
||||
target_zig_str(target),
|
||||
opt_level,
|
||||
shared_lib_path,
|
||||
)
|
||||
}
|
||||
Architecture::Aarch64(_) => build_zig_host_native(
|
||||
&env_path,
|
||||
&env_home,
|
||||
host_dest.to_str().unwrap(),
|
||||
zig_host_src.to_str().unwrap(),
|
||||
zig_str_path.to_str().unwrap(),
|
||||
target_zig_str(target),
|
||||
opt_level,
|
||||
shared_lib_path,
|
||||
),
|
||||
_ => internal_error!("Unsupported architecture {:?}", target.architecture),
|
||||
};
|
||||
|
||||
validate_output("host.zig", &zig_executable(), output)
|
||||
run_build_command(zig_cmd, "host.zig")
|
||||
} else if cargo_host_src.exists() {
|
||||
// Compile and link Cargo.toml, if it exists
|
||||
let cargo_dir = host_input_path.parent().unwrap();
|
||||
|
@ -646,25 +632,23 @@ pub fn rebuild_host(
|
|||
},
|
||||
);
|
||||
|
||||
let mut command = Command::new("cargo");
|
||||
command.arg("build").current_dir(cargo_dir);
|
||||
let mut cargo_cmd = cargo();
|
||||
cargo_cmd.arg("build").current_dir(cargo_dir);
|
||||
// Rust doesn't expose size without editing the cargo.toml. Instead just use release.
|
||||
if matches!(opt_level, OptLevel::Optimize | OptLevel::Size) {
|
||||
command.arg("--release");
|
||||
cargo_cmd.arg("--release");
|
||||
}
|
||||
|
||||
let source_file = if shared_lib_path.is_some() {
|
||||
command.env("RUSTFLAGS", "-C link-dead-code");
|
||||
command.args(&["--bin", "host"]);
|
||||
cargo_cmd.env("RUSTFLAGS", "-C link-dead-code");
|
||||
cargo_cmd.args(["--bin", "host"]);
|
||||
"src/main.rs"
|
||||
} else {
|
||||
command.arg("--lib");
|
||||
cargo_cmd.arg("--lib");
|
||||
"src/lib.rs"
|
||||
};
|
||||
|
||||
let output = command.output().unwrap();
|
||||
|
||||
validate_output(source_file, "cargo build", output);
|
||||
run_build_command(cargo_cmd, source_file);
|
||||
|
||||
if shared_lib_path.is_some() {
|
||||
// For surgical linking, just copy the dynamically linked rust app.
|
||||
|
@ -674,7 +658,7 @@ pub fn rebuild_host(
|
|||
} else {
|
||||
// Cargo hosts depend on a c wrapper for the api. Compile host.c as well.
|
||||
|
||||
let output = build_c_host_native(
|
||||
let clang_cmd = build_c_host_native(
|
||||
target,
|
||||
&env_path,
|
||||
&env_home,
|
||||
|
@ -684,23 +668,22 @@ pub fn rebuild_host(
|
|||
opt_level,
|
||||
shared_lib_path,
|
||||
);
|
||||
validate_output("host.c", "clang", output);
|
||||
|
||||
let output = Command::new("ld")
|
||||
.env_clear()
|
||||
.env("PATH", &env_path)
|
||||
.args(&[
|
||||
"-r",
|
||||
"-L",
|
||||
cargo_out_dir.to_str().unwrap(),
|
||||
c_host_dest.to_str().unwrap(),
|
||||
"-lhost",
|
||||
"-o",
|
||||
host_dest.to_str().unwrap(),
|
||||
])
|
||||
.output()
|
||||
.unwrap();
|
||||
validate_output("c_host.o", "ld", output);
|
||||
run_build_command(clang_cmd, "host.c");
|
||||
|
||||
let mut ld_cmd = Command::new("ld");
|
||||
|
||||
ld_cmd.env_clear().env("PATH", &env_path).args([
|
||||
"-r",
|
||||
"-L",
|
||||
cargo_out_dir.to_str().unwrap(),
|
||||
c_host_dest.to_str().unwrap(),
|
||||
"-lhost",
|
||||
"-o",
|
||||
host_dest.to_str().unwrap(),
|
||||
]);
|
||||
|
||||
run_build_command(ld_cmd, "c_host.o");
|
||||
|
||||
// Clean up c_host.o
|
||||
if c_host_dest.exists() {
|
||||
|
@ -709,25 +692,24 @@ pub fn rebuild_host(
|
|||
}
|
||||
} else if rust_host_src.exists() {
|
||||
// Compile and link host.rs, if it exists
|
||||
let mut command = Command::new("rustc");
|
||||
command.args(&[
|
||||
let mut rustc_cmd = Command::new("rustc");
|
||||
rustc_cmd.args([
|
||||
rust_host_src.to_str().unwrap(),
|
||||
"-o",
|
||||
rust_host_dest.to_str().unwrap(),
|
||||
]);
|
||||
if matches!(opt_level, OptLevel::Optimize) {
|
||||
command.arg("-O");
|
||||
rustc_cmd.arg("-O");
|
||||
} else if matches!(opt_level, OptLevel::Size) {
|
||||
command.arg("-C opt-level=s");
|
||||
rustc_cmd.arg("-C opt-level=s");
|
||||
}
|
||||
let output = command.output().unwrap();
|
||||
|
||||
validate_output("host.rs", "rustc", output);
|
||||
run_build_command(rustc_cmd, "host.rs");
|
||||
|
||||
// Rust hosts depend on a c wrapper for the api. Compile host.c as well.
|
||||
if shared_lib_path.is_some() {
|
||||
// If compiling to executable, let c deal with linking as well.
|
||||
let output = build_c_host_native(
|
||||
let clang_cmd = build_c_host_native(
|
||||
target,
|
||||
&env_path,
|
||||
&env_home,
|
||||
|
@ -740,9 +722,9 @@ pub fn rebuild_host(
|
|||
opt_level,
|
||||
shared_lib_path,
|
||||
);
|
||||
validate_output("host.c", "clang", output);
|
||||
run_build_command(clang_cmd, "host.c");
|
||||
} else {
|
||||
let output = build_c_host_native(
|
||||
let clang_cmd = build_c_host_native(
|
||||
target,
|
||||
&env_path,
|
||||
&env_home,
|
||||
|
@ -753,21 +735,19 @@ pub fn rebuild_host(
|
|||
shared_lib_path,
|
||||
);
|
||||
|
||||
validate_output("host.c", "clang", output);
|
||||
let output = Command::new("ld")
|
||||
.env_clear()
|
||||
.env("PATH", &env_path)
|
||||
.args(&[
|
||||
"-r",
|
||||
c_host_dest.to_str().unwrap(),
|
||||
rust_host_dest.to_str().unwrap(),
|
||||
"-o",
|
||||
host_dest.to_str().unwrap(),
|
||||
])
|
||||
.output()
|
||||
.unwrap();
|
||||
run_build_command(clang_cmd, "host.c");
|
||||
|
||||
validate_output("rust_host.o", "ld", output);
|
||||
let mut ld_cmd = Command::new("ld");
|
||||
|
||||
ld_cmd.env_clear().env("PATH", &env_path).args([
|
||||
"-r",
|
||||
c_host_dest.to_str().unwrap(),
|
||||
rust_host_dest.to_str().unwrap(),
|
||||
"-o",
|
||||
host_dest.to_str().unwrap(),
|
||||
]);
|
||||
|
||||
run_build_command(ld_cmd, "rust_host.o");
|
||||
}
|
||||
|
||||
// Clean up rust_host.o and c_host.o
|
||||
|
@ -779,7 +759,7 @@ pub fn rebuild_host(
|
|||
}
|
||||
} else if c_host_src.exists() {
|
||||
// Compile host.c, if it exists
|
||||
let output = build_c_host_native(
|
||||
let clang_cmd = build_c_host_native(
|
||||
target,
|
||||
&env_path,
|
||||
&env_home,
|
||||
|
@ -789,10 +769,11 @@ pub fn rebuild_host(
|
|||
opt_level,
|
||||
shared_lib_path,
|
||||
);
|
||||
validate_output("host.c", "clang", output);
|
||||
|
||||
run_build_command(clang_cmd, "host.c");
|
||||
} else if swift_host_src.exists() {
|
||||
// Compile host.swift, if it exists
|
||||
let output = build_swift_host_native(
|
||||
let swiftc_cmd = build_swift_host_native(
|
||||
&env_path,
|
||||
&env_home,
|
||||
host_dest.to_str().unwrap(),
|
||||
|
@ -804,7 +785,8 @@ pub fn rebuild_host(
|
|||
.then(|| swift_host_header_src.to_str().unwrap()),
|
||||
target.architecture,
|
||||
);
|
||||
validate_output("host.swift", "swiftc", output);
|
||||
|
||||
run_build_command(swiftc_cmd, "host.swift");
|
||||
}
|
||||
|
||||
host_dest
|
||||
|
@ -873,10 +855,10 @@ fn link_linux(
|
|||
|
||||
if let Architecture::X86_32(_) = target.architecture {
|
||||
return Ok((
|
||||
Command::new(&zig_executable())
|
||||
.args(&["build-exe"])
|
||||
zig()
|
||||
.args(["build-exe"])
|
||||
.args(input_paths)
|
||||
.args(&[
|
||||
.args([
|
||||
"-target",
|
||||
"i386-linux-musl",
|
||||
"-lc",
|
||||
|
@ -1029,7 +1011,7 @@ fn link_linux(
|
|||
.filter(|&(ref k, _)| k.starts_with("NIX_"))
|
||||
.collect::<HashMap<String, String>>(),
|
||||
)
|
||||
.args(&[
|
||||
.args([
|
||||
"--gc-sections",
|
||||
"--eh-frame-hdr",
|
||||
"-A",
|
||||
|
@ -1039,11 +1021,11 @@ fn link_linux(
|
|||
&*crtn_path.to_string_lossy(),
|
||||
])
|
||||
.args(&base_args)
|
||||
.args(&["-dynamic-linker", ld_linux])
|
||||
.args(["-dynamic-linker", ld_linux])
|
||||
.args(input_paths)
|
||||
// ld.lld requires this argument, and does not accept --arch
|
||||
// .args(&["-L/usr/lib/x86_64-linux-gnu"])
|
||||
.args(&[
|
||||
.args([
|
||||
// Libraries - see https://github.com/roc-lang/roc/pull/554#discussion_r496365925
|
||||
// for discussion and further references
|
||||
"-lc",
|
||||
|
@ -1094,7 +1076,7 @@ fn link_macos(
|
|||
// The `-l` flags should go after the `.o` arguments
|
||||
// Don't allow LD_ env vars to affect this
|
||||
.env_clear()
|
||||
.args(&[
|
||||
.args([
|
||||
// NOTE: we don't do --gc-sections on macOS because the default
|
||||
// macOS linker doesn't support it, but it's a performance
|
||||
// optimization, so if we ever switch to a different linker,
|
||||
|
@ -1126,7 +1108,7 @@ fn link_macos(
|
|||
ld_command.arg(roc_link_flag);
|
||||
}
|
||||
|
||||
ld_command.args(&[
|
||||
ld_command.args([
|
||||
// Libraries - see https://github.com/roc-lang/roc/pull/554#discussion_r496392274
|
||||
// for discussion and further references
|
||||
"-lSystem",
|
||||
|
@ -1166,7 +1148,7 @@ fn link_macos(
|
|||
Architecture::Aarch64(_) => {
|
||||
ld_child.wait()?;
|
||||
let codesign_child = Command::new("codesign")
|
||||
.args(&["-s", "-", output_path.to_str().unwrap()])
|
||||
.args(["-s", "-", output_path.to_str().unwrap()])
|
||||
.spawn()?;
|
||||
|
||||
Ok((codesign_child, output_path))
|
||||
|
@ -1202,10 +1184,10 @@ fn link_wasm32(
|
|||
let zig_str_path = find_zig_str_path();
|
||||
let wasi_libc_path = find_wasi_libc_path();
|
||||
|
||||
let child = Command::new(&zig_executable())
|
||||
let child = zig()
|
||||
// .env_clear()
|
||||
// .env("PATH", &env_path)
|
||||
.args(&["build-exe"])
|
||||
.args(["build-exe"])
|
||||
.args(input_paths)
|
||||
.args([
|
||||
// include wasi libc
|
||||
|
@ -1239,8 +1221,8 @@ fn link_windows(
|
|||
|
||||
match link_type {
|
||||
LinkType::Dylib => {
|
||||
let child = Command::new(&zig_executable())
|
||||
.args(&["build-lib"])
|
||||
let child = zig()
|
||||
.args(["build-lib"])
|
||||
.args(input_paths)
|
||||
.args([
|
||||
"-lc",
|
||||
|
@ -1261,8 +1243,8 @@ fn link_windows(
|
|||
Ok((child, output_path))
|
||||
}
|
||||
LinkType::Executable => {
|
||||
let child = Command::new(&zig_executable())
|
||||
.args(&["build-exe"])
|
||||
let child = zig()
|
||||
.args(["build-exe"])
|
||||
.args(input_paths)
|
||||
.args([
|
||||
"-target",
|
||||
|
@ -1349,7 +1331,7 @@ pub fn preprocess_host_wasm32(host_input_path: &Path, preprocessed_host_path: &P
|
|||
(but seems to be an unofficial API)
|
||||
*/
|
||||
|
||||
let mut command = Command::new(&zig_executable());
|
||||
let mut zig_cmd = zig();
|
||||
let args = &[
|
||||
"wasm-ld",
|
||||
&bitcode::get_builtins_wasm32_obj_path(),
|
||||
|
@ -1364,28 +1346,30 @@ pub fn preprocess_host_wasm32(host_input_path: &Path, preprocessed_host_path: &P
|
|||
"--relocatable",
|
||||
];
|
||||
|
||||
command.args(args);
|
||||
zig_cmd.args(args);
|
||||
|
||||
// println!("\npreprocess_host_wasm32");
|
||||
// println!("zig {}\n", args.join(" "));
|
||||
|
||||
let output = command.output().unwrap();
|
||||
validate_output(output_file, "zig", output)
|
||||
run_build_command(zig_cmd, output_file)
|
||||
}
|
||||
|
||||
fn validate_output(file_name: &str, cmd_name: &str, output: Output) {
|
||||
if !output.status.success() {
|
||||
match std::str::from_utf8(&output.stderr) {
|
||||
fn run_build_command(mut command: Command, file_to_build: &str) {
|
||||
let cmd_str = format!("{:?}", &command);
|
||||
let cmd_output = command.output().unwrap();
|
||||
|
||||
if !cmd_output.status.success() {
|
||||
match std::str::from_utf8(&cmd_output.stderr) {
|
||||
Ok(stderr) => internal_error!(
|
||||
"Failed to rebuild {} - stderr of the `{}` command was:\n{}",
|
||||
file_name,
|
||||
cmd_name,
|
||||
"Error:\n Failed to rebuild {}:\n The executed command was:\n {}\n stderr of that command:\n {}",
|
||||
file_to_build,
|
||||
cmd_str,
|
||||
stderr
|
||||
),
|
||||
Err(utf8_err) => internal_error!(
|
||||
"Failed to rebuild {} - stderr of the `{}` command was invalid utf8 ({:?})",
|
||||
file_name,
|
||||
cmd_name,
|
||||
"Error:\n Failed to rebuild {}:\n The executed command was:\n {}\n stderr of that command could not be parsed as valid utf8:\n {}",
|
||||
file_to_build,
|
||||
cmd_str,
|
||||
utf8_err
|
||||
),
|
||||
}
|
||||
|
|
|
@ -347,7 +347,7 @@ fn gen_from_mono_module_llvm(
|
|||
|
||||
// run the debugir https://github.com/vaivaswatha/debugir tool
|
||||
match Command::new("debugir")
|
||||
.args(&["-instnamer", app_ll_file.to_str().unwrap()])
|
||||
.args(["-instnamer", app_ll_file.to_str().unwrap()])
|
||||
.output()
|
||||
{
|
||||
Ok(_) => {}
|
||||
|
@ -369,7 +369,7 @@ fn gen_from_mono_module_llvm(
|
|||
| Architecture::Aarch64(_)
|
||||
| Architecture::Wasm32 => {
|
||||
let ll_to_bc = Command::new("llvm-as")
|
||||
.args(&[
|
||||
.args([
|
||||
app_ll_dbg_file.to_str().unwrap(),
|
||||
"-o",
|
||||
app_bc_file.to_str().unwrap(),
|
||||
|
|
|
@ -16,6 +16,7 @@ lazy_static = "1.4.0"
|
|||
[build-dependencies]
|
||||
# dunce can be removed once ziglang/zig#5109 is fixed
|
||||
dunce = "1.0.3"
|
||||
roc_utils = { path = "../../utils" }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.build-dependencies]
|
||||
tempfile = "3.2.0"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
|
||||
set -euxo pipefail
|
||||
|
||||
zig build-exe benchmark/dec.zig -O ReleaseFast --main-pkg-path .
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::convert::AsRef;
|
||||
use roc_utils::zig;
|
||||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
@ -14,13 +13,6 @@ use tempfile::tempdir;
|
|||
/// To debug the zig code with debug prints, we need to disable the wasm code gen
|
||||
const DEBUG: bool = false;
|
||||
|
||||
fn zig_executable() -> String {
|
||||
match std::env::var("ROC_ZIG") {
|
||||
Ok(path) => path,
|
||||
Err(_) => "zig".into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
|
@ -95,12 +87,13 @@ fn generate_object_file(bitcode_path: &Path, zig_object: &str, object_file_name:
|
|||
println!("Compiling zig object `{}` to: {}", zig_object, src_obj);
|
||||
|
||||
if !DEBUG {
|
||||
run_command(
|
||||
&bitcode_path,
|
||||
&zig_executable(),
|
||||
&["build", zig_object, "-Drelease=true"],
|
||||
0,
|
||||
);
|
||||
let mut zig_cmd = zig();
|
||||
|
||||
zig_cmd
|
||||
.current_dir(bitcode_path)
|
||||
.args(["build", zig_object, "-Drelease=true"]);
|
||||
|
||||
run_command(zig_cmd, 0);
|
||||
|
||||
println!("Moving zig object `{}` to: {}", zig_object, dest_obj);
|
||||
|
||||
|
@ -130,12 +123,13 @@ fn generate_bc_file(bitcode_path: &Path, zig_object: &str, file_name: &str) {
|
|||
#[cfg(target_os = "macos")]
|
||||
let _ = fs::remove_dir_all("./bitcode/zig-cache");
|
||||
|
||||
run_command(
|
||||
&bitcode_path,
|
||||
&zig_executable(),
|
||||
&["build", zig_object, "-Drelease=true"],
|
||||
0,
|
||||
);
|
||||
let mut zig_cmd = zig();
|
||||
|
||||
zig_cmd
|
||||
.current_dir(bitcode_path)
|
||||
.args(["build", zig_object, "-Drelease=true"]);
|
||||
|
||||
run_command(zig_cmd, 0);
|
||||
}
|
||||
|
||||
pub fn get_lib_dir() -> PathBuf {
|
||||
|
@ -174,7 +168,7 @@ fn copy_zig_builtins_to_target_dir(bitcode_path: &Path) {
|
|||
// recursively copy all the .zig files from this directory, but do *not* recurse into zig-cache/
|
||||
fn cp_unless_zig_cache(src_dir: &Path, target_dir: &Path) -> io::Result<()> {
|
||||
// Make sure the destination directory exists before we try to copy anything into it.
|
||||
std::fs::create_dir_all(&target_dir).unwrap_or_else(|err| {
|
||||
std::fs::create_dir_all(target_dir).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"Failed to create output library directory for zig bitcode {:?}: {:?}",
|
||||
target_dir, err
|
||||
|
@ -204,19 +198,10 @@ fn cp_unless_zig_cache(src_dir: &Path, target_dir: &Path) -> io::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn run_command<S, I: Copy, P: AsRef<Path> + Copy>(
|
||||
path: P,
|
||||
command_str: &str,
|
||||
args: I,
|
||||
flaky_fail_counter: usize,
|
||||
) where
|
||||
I: IntoIterator<Item = S>,
|
||||
S: AsRef<OsStr>,
|
||||
{
|
||||
let output_result = Command::new(OsStr::new(&command_str))
|
||||
.current_dir(path)
|
||||
.args(args)
|
||||
.output();
|
||||
fn run_command(mut command: Command, flaky_fail_counter: usize) {
|
||||
let command_str = format!("{:?}", &command);
|
||||
|
||||
let output_result = command.output();
|
||||
|
||||
match output_result {
|
||||
Ok(output) => match output.status.success() {
|
||||
|
@ -227,14 +212,14 @@ fn run_command<S, I: Copy, P: AsRef<Path> + Copy>(
|
|||
Err(_) => format!("Failed to run \"{}\"", command_str),
|
||||
};
|
||||
|
||||
// flaky test error that only occurs sometimes inside MacOS ci run
|
||||
// Flaky test errors that only occur sometimes on MacOS ci server.
|
||||
if error_str.contains("FileNotFound")
|
||||
|| error_str.contains("unable to save cached ZIR code")
|
||||
{
|
||||
if flaky_fail_counter == 10 {
|
||||
panic!("{} failed 10 times in a row. The following error is unlikely to be a flaky error: {}", command_str, error_str);
|
||||
} else {
|
||||
run_command(path, command_str, args, flaky_fail_counter + 1)
|
||||
run_command(command, flaky_fail_counter + 1)
|
||||
}
|
||||
} else {
|
||||
panic!("{} failed: {}", command_str, error_str);
|
||||
|
|
|
@ -223,18 +223,18 @@ expect update (single "a" Bool.true) "a" alterValue == empty
|
|||
## Dict.empty
|
||||
## |> Dict.insert 1234 "5678"
|
||||
## |> Dict.contains 1234
|
||||
## |> Bool.isEq Bool.true
|
||||
contains : Dict k v, k -> Bool | k has Eq
|
||||
contains = \@Dict list, needle ->
|
||||
step = \_, Pair key _val ->
|
||||
if key == needle then
|
||||
Break {}
|
||||
else
|
||||
Continue {}
|
||||
List.any list \Pair key _val -> key == needle
|
||||
|
||||
when List.iterate list {} step is
|
||||
Continue _ -> Bool.false
|
||||
Break _ -> Bool.true
|
||||
expect contains empty "a" == Bool.false
|
||||
expect contains (single "a" {}) "a" == Bool.true
|
||||
expect contains (single "b" {}) "a" == Bool.false
|
||||
expect
|
||||
Dict.empty
|
||||
|> Dict.insert 1234 "5678"
|
||||
|> Dict.contains 1234
|
||||
|> Bool.isEq Bool.true
|
||||
|
||||
## Returns a dictionary containing the key and value provided as input.
|
||||
##
|
||||
|
|
|
@ -8,7 +8,6 @@ interface List
|
|||
map,
|
||||
len,
|
||||
withCapacity,
|
||||
iterate,
|
||||
walkBackwards,
|
||||
concat,
|
||||
first,
|
||||
|
|
|
@ -28,7 +28,7 @@ pub struct MemberVariables {
|
|||
|
||||
/// The member and its signature is defined locally, in the module the store is created for.
|
||||
/// We need to instantiate and introduce this during solving.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ResolvedMemberType(Variable);
|
||||
|
||||
/// Member type information that needs to be resolved from imports.
|
||||
|
@ -56,7 +56,7 @@ impl ResolvePhase for Pending {
|
|||
type MemberType = PendingMemberType;
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Resolved;
|
||||
impl ResolvePhase for Resolved {
|
||||
type MemberType = ResolvedMemberType;
|
||||
|
|
|
@ -13,13 +13,14 @@ use roc_types::types::{Category, PatternCategory, Type};
|
|||
pub struct Constraints {
|
||||
pub constraints: Vec<Constraint>,
|
||||
pub types: Vec<Cell<Type>>,
|
||||
pub type_slices: Vec<TypeOrVar>,
|
||||
pub variables: Vec<Variable>,
|
||||
pub loc_symbols: Vec<(Symbol, Region)>,
|
||||
pub let_constraints: Vec<LetConstraint>,
|
||||
pub categories: Vec<Category>,
|
||||
pub pattern_categories: Vec<PatternCategory>,
|
||||
pub expectations: Vec<Expected<Cell<Type>>>,
|
||||
pub pattern_expectations: Vec<PExpected<Cell<Type>>>,
|
||||
pub expectations: Vec<Expected<TypeOrVar>>,
|
||||
pub pattern_expectations: Vec<PExpected<TypeOrVar>>,
|
||||
pub includes_tags: Vec<IncludesTag>,
|
||||
pub strings: Vec<&'static str>,
|
||||
pub sketched_rows: Vec<SketchedRows>,
|
||||
|
@ -33,6 +34,7 @@ impl std::fmt::Debug for Constraints {
|
|||
f.debug_struct("Constraints")
|
||||
.field("constraints", &self.constraints)
|
||||
.field("types", &"<types>")
|
||||
.field("type_slices", &self.type_slices)
|
||||
.field("variables", &self.variables)
|
||||
.field("loc_symbols", &self.loc_symbols)
|
||||
.field("let_constraints", &self.let_constraints)
|
||||
|
@ -56,15 +58,15 @@ impl Default for Constraints {
|
|||
}
|
||||
}
|
||||
|
||||
pub type TypeIndex = Index<Cell<Type>>;
|
||||
pub type ExpectedTypeIndex = Index<Expected<Cell<Type>>>;
|
||||
pub type PExpectedTypeIndex = Index<PExpected<Cell<Type>>>;
|
||||
pub type ExpectedTypeIndex = Index<Expected<TypeOrVar>>;
|
||||
pub type PExpectedTypeIndex = Index<PExpected<TypeOrVar>>;
|
||||
pub type TypeOrVar = EitherIndex<Cell<Type>, Variable>;
|
||||
|
||||
impl Constraints {
|
||||
pub fn new() -> Self {
|
||||
let constraints = Vec::new();
|
||||
let mut types = Vec::new();
|
||||
let type_slices = Vec::with_capacity(16);
|
||||
let variables = Vec::new();
|
||||
let loc_symbols = Vec::new();
|
||||
let let_constraints = Vec::new();
|
||||
|
@ -119,6 +121,7 @@ impl Constraints {
|
|||
Self {
|
||||
constraints,
|
||||
types,
|
||||
type_slices,
|
||||
variables,
|
||||
loc_symbols,
|
||||
let_constraints,
|
||||
|
@ -211,12 +214,12 @@ impl Constraints {
|
|||
EitherIndex::from_right(index)
|
||||
}
|
||||
|
||||
pub fn push_expected_type(&mut self, expected: Expected<Type>) -> ExpectedTypeIndex {
|
||||
Index::push_new(&mut self.expectations, expected.map(Cell::new))
|
||||
pub fn push_expected_type(&mut self, expected: Expected<TypeOrVar>) -> ExpectedTypeIndex {
|
||||
Index::push_new(&mut self.expectations, expected)
|
||||
}
|
||||
|
||||
pub fn push_pat_expected_type(&mut self, expected: PExpected<Type>) -> PExpectedTypeIndex {
|
||||
Index::push_new(&mut self.pattern_expectations, expected.map(Cell::new))
|
||||
pub fn push_pat_expected_type(&mut self, expected: PExpected<TypeOrVar>) -> PExpectedTypeIndex {
|
||||
Index::push_new(&mut self.pattern_expectations, expected)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -372,24 +375,24 @@ impl Constraints {
|
|||
|
||||
fn def_types_slice<I>(&mut self, it: I) -> DefTypes
|
||||
where
|
||||
I: IntoIterator<Item = (Symbol, Loc<Type>)>,
|
||||
I: IntoIterator<Item = (Symbol, Loc<TypeOrVar>)>,
|
||||
I::IntoIter: ExactSizeIterator,
|
||||
{
|
||||
let it = it.into_iter();
|
||||
|
||||
let types_start = self.types.len();
|
||||
let types_start = self.type_slices.len();
|
||||
let loc_symbols_start = self.loc_symbols.len();
|
||||
|
||||
// because we have an ExactSizeIterator, we can reserve space here
|
||||
let length = it.len();
|
||||
|
||||
self.types.reserve(length);
|
||||
self.type_slices.reserve(length);
|
||||
self.loc_symbols.reserve(length);
|
||||
|
||||
for (symbol, loc_type) in it {
|
||||
let Loc { region, value } = loc_type;
|
||||
|
||||
self.types.push(Cell::new(value));
|
||||
self.type_slices.push(value);
|
||||
self.loc_symbols.push((symbol, region));
|
||||
}
|
||||
|
||||
|
@ -460,7 +463,7 @@ impl Constraints {
|
|||
where
|
||||
I1: IntoIterator<Item = Variable>,
|
||||
I2: IntoIterator<Item = Variable>,
|
||||
I3: IntoIterator<Item = (Symbol, Loc<Type>)>,
|
||||
I3: IntoIterator<Item = (Symbol, Loc<TypeOrVar>)>,
|
||||
I3::IntoIter: ExactSizeIterator,
|
||||
{
|
||||
// defs and ret constraint are stored consequtively, so we only need to store one index
|
||||
|
@ -506,7 +509,7 @@ impl Constraints {
|
|||
) -> Constraint
|
||||
where
|
||||
I1: IntoIterator<Item = Variable>,
|
||||
I2: IntoIterator<Item = (Symbol, Loc<Type>)>,
|
||||
I2: IntoIterator<Item = (Symbol, Loc<TypeOrVar>)>,
|
||||
I2::IntoIter: ExactSizeIterator,
|
||||
{
|
||||
// defs and ret constraint are stored consequtively, so we only need to store one index
|
||||
|
@ -615,8 +618,8 @@ impl Constraints {
|
|||
real_var: Variable,
|
||||
real_region: Region,
|
||||
category_and_expectation: Result<
|
||||
(Category, Expected<Type>),
|
||||
(PatternCategory, PExpected<Type>),
|
||||
(Category, ExpectedTypeIndex),
|
||||
(PatternCategory, PExpectedTypeIndex),
|
||||
>,
|
||||
sketched_rows: SketchedRows,
|
||||
context: ExhaustiveContext,
|
||||
|
@ -628,15 +631,12 @@ impl Constraints {
|
|||
let equality = match category_and_expectation {
|
||||
Ok((category, expected)) => {
|
||||
let category = Index::push_new(&mut self.categories, category);
|
||||
let expected = Index::push_new(&mut self.expectations, expected.map(Cell::new));
|
||||
let equality = Eq(real_var, expected, category, real_region);
|
||||
let equality = Index::push_new(&mut self.eq, equality);
|
||||
Ok(equality)
|
||||
}
|
||||
Err((category, expected)) => {
|
||||
let category = Index::push_new(&mut self.pattern_categories, category);
|
||||
let expected =
|
||||
Index::push_new(&mut self.pattern_expectations, expected.map(Cell::new));
|
||||
let equality = PatternEq(real_var, expected, category, real_region);
|
||||
let equality = Index::push_new(&mut self.pattern_eq, equality);
|
||||
Err(equality)
|
||||
|
@ -679,7 +679,7 @@ roc_error_macros::assert_sizeof_aarch64!(Constraint, 3 * 8);
|
|||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Eq(
|
||||
pub TypeOrVar,
|
||||
pub Index<Expected<Cell<Type>>>,
|
||||
pub ExpectedTypeIndex,
|
||||
pub Index<Category>,
|
||||
pub Region,
|
||||
);
|
||||
|
@ -759,7 +759,7 @@ pub enum Constraint {
|
|||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct DefTypes {
|
||||
pub types: Slice<Type>,
|
||||
pub types: Slice<TypeOrVar>,
|
||||
pub loc_symbols: Slice<(Symbol, Region)>,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
def::Def,
|
||||
expr::{AccessorData, ClosureData, Expr, Field, OpaqueWrapFunctionData, WhenBranchPattern},
|
||||
pattern::{DestructType, Pattern, RecordDestruct},
|
||||
pattern::{DestructType, ListPatterns, Pattern, RecordDestruct},
|
||||
};
|
||||
use roc_module::{
|
||||
ident::{Lowercase, TagName},
|
||||
|
@ -707,6 +707,18 @@ fn deep_copy_pattern_help<C: CopyEnv>(
|
|||
})
|
||||
.collect(),
|
||||
},
|
||||
List {
|
||||
list_var,
|
||||
elem_var,
|
||||
patterns: ListPatterns { patterns, opt_rest },
|
||||
} => List {
|
||||
list_var: sub!(*list_var),
|
||||
elem_var: sub!(*elem_var),
|
||||
patterns: ListPatterns {
|
||||
patterns: patterns.iter().map(|lp| lp.map(|p| go_help!(p))).collect(),
|
||||
opt_rest: *opt_rest,
|
||||
},
|
||||
},
|
||||
NumLiteral(var, s, n, bound) => NumLiteral(sub!(*var), s.clone(), *n, *bound),
|
||||
IntLiteral(v1, v2, s, n, bound) => IntLiteral(sub!(*v1), sub!(*v2), s.clone(), *n, *bound),
|
||||
FloatLiteral(v1, v2, s, n, bound) => {
|
||||
|
|
|
@ -1821,7 +1821,7 @@ pub(crate) fn sort_can_defs(
|
|||
.strongly_connected_components_subset(group);
|
||||
|
||||
debug_assert!(
|
||||
!group.iter_ones().any(|index| matches!((&defs[index]).as_ref().unwrap().loc_pattern.value, Pattern::AbilityMemberSpecialization{..})),
|
||||
!group.iter_ones().any(|index| matches!(defs[index].as_ref().unwrap().loc_pattern.value, Pattern::AbilityMemberSpecialization{..})),
|
||||
"A specialization is involved in a recursive cycle - this should not be knowable until solving");
|
||||
|
||||
let declaration = if direct_sccs.groups().count() == 1 {
|
||||
|
@ -1921,6 +1921,14 @@ fn pattern_to_vars_by_symbol(
|
|||
}
|
||||
}
|
||||
|
||||
List {
|
||||
patterns, elem_var, ..
|
||||
} => {
|
||||
for pat in patterns.patterns.iter() {
|
||||
pattern_to_vars_by_symbol(vars_by_symbol, &pat.value, *elem_var);
|
||||
}
|
||||
}
|
||||
|
||||
NumLiteral(..)
|
||||
| IntLiteral(..)
|
||||
| FloatLiteral(..)
|
||||
|
|
|
@ -4,11 +4,14 @@ use roc_collections::all::HumanIndex;
|
|||
use roc_collections::VecMap;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_exhaustive::{
|
||||
is_useful, Ctor, CtorName, Error, Guard, Literal, Pattern, RenderAs, TagId, Union,
|
||||
is_useful, Ctor, CtorName, Error, Guard, ListArity, Literal, Pattern, RenderAs, TagId, Union,
|
||||
};
|
||||
use roc_module::ident::{TagIdIntType, TagName};
|
||||
use roc_module::ident::{Lowercase, TagIdIntType, TagName};
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::{Content, FlatType, RedundantMark, Subs, SubsFmtContent, Variable};
|
||||
use roc_types::subs::{
|
||||
Content, FlatType, GetSubsSlice, RedundantMark, Subs, SubsFmtContent, Variable,
|
||||
};
|
||||
use roc_types::types::AliasKind;
|
||||
|
||||
pub use roc_exhaustive::Context as ExhaustiveContext;
|
||||
|
@ -22,12 +25,19 @@ pub struct ExhaustiveSummary {
|
|||
pub redundancies: Vec<RedundantMark>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TypeError;
|
||||
|
||||
/// Exhaustiveness-checks [sketched rows][SketchedRows] against an expected type.
|
||||
///
|
||||
/// Returns an error if the sketch has a type error, in which case exhautiveness checking will not
|
||||
/// have been performed.
|
||||
pub fn check(
|
||||
subs: &Subs,
|
||||
real_var: Variable,
|
||||
sketched_rows: SketchedRows,
|
||||
context: ExhaustiveContext,
|
||||
) -> ExhaustiveSummary {
|
||||
) -> Result<ExhaustiveSummary, TypeError> {
|
||||
let overall_region = sketched_rows.overall_region;
|
||||
let mut all_errors = Vec::with_capacity(1);
|
||||
|
||||
|
@ -35,7 +45,7 @@ pub fn check(
|
|||
non_redundant_rows,
|
||||
errors,
|
||||
redundancies,
|
||||
} = sketched_rows.reify_to_non_redundant(subs, real_var);
|
||||
} = sketched_rows.reify_to_non_redundant(subs, real_var)?;
|
||||
all_errors.extend(errors);
|
||||
|
||||
let exhaustive = match roc_exhaustive::check(overall_region, context, non_redundant_rows) {
|
||||
|
@ -46,11 +56,11 @@ pub fn check(
|
|||
}
|
||||
};
|
||||
|
||||
ExhaustiveSummary {
|
||||
Ok(ExhaustiveSummary {
|
||||
errors: all_errors,
|
||||
exhaustive,
|
||||
redundancies,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -60,7 +70,8 @@ enum SketchedPattern {
|
|||
/// A constructor whose expected union is not yet known.
|
||||
/// We'll know the whole union when reifying the sketched pattern against an expected case type.
|
||||
Ctor(TagName, Vec<SketchedPattern>),
|
||||
KnownCtor(Union, IndexCtor<'static>, TagId, Vec<SketchedPattern>),
|
||||
KnownCtor(Union, TagId, Vec<SketchedPattern>),
|
||||
List(ListArity, Vec<SketchedPattern>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -68,12 +79,42 @@ enum IndexCtor<'a> {
|
|||
/// Index an opaque type. There should be one argument.
|
||||
Opaque,
|
||||
/// Index a record type. The arguments are the types of the record fields.
|
||||
Record,
|
||||
Record(&'a [Lowercase]),
|
||||
/// Index a guard constructor. The arguments are a faux guard pattern, and then the real
|
||||
/// pattern being guarded. E.g. `A B if g` becomes Guard { [True, (A B)] }.
|
||||
Guard,
|
||||
/// Index a tag union with the given tag constructor.
|
||||
Tag(&'a TagName),
|
||||
/// Index a list type. The argument is the element type.
|
||||
List,
|
||||
}
|
||||
|
||||
impl<'a> IndexCtor<'a> {
|
||||
fn of_union(un: &'a Union, tag_id: TagId) -> Self {
|
||||
let Union {
|
||||
alternatives,
|
||||
render_as,
|
||||
} = un;
|
||||
|
||||
match render_as {
|
||||
RenderAs::Tag => {
|
||||
let tag_name = alternatives
|
||||
.iter()
|
||||
.find(|ctor| ctor.tag_id == tag_id)
|
||||
.map(|Ctor { name, .. }| match name {
|
||||
CtorName::Tag(tag) => tag,
|
||||
CtorName::Opaque(_) => {
|
||||
internal_error!("tag union should never have opaque alternative")
|
||||
}
|
||||
})
|
||||
.expect("indexable tag ID must be known to alternatives");
|
||||
Self::Tag(tag_name)
|
||||
}
|
||||
RenderAs::Opaque => Self::Opaque,
|
||||
RenderAs::Record(fields) => Self::Record(fields),
|
||||
RenderAs::Guard => Self::Guard,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Index a variable as a certain constructor, to get the expected argument types of that constructor.
|
||||
|
@ -82,11 +123,11 @@ fn index_var(
|
|||
mut var: Variable,
|
||||
ctor: IndexCtor,
|
||||
render_as: &RenderAs,
|
||||
) -> Vec<Variable> {
|
||||
) -> Result<Vec<Variable>, TypeError> {
|
||||
if matches!(ctor, IndexCtor::Guard) {
|
||||
// `A B if g` becomes Guard { [True, (A B)] }, so the arguments are a bool, and the type
|
||||
// of the pattern.
|
||||
return vec![Variable::BOOL, var];
|
||||
return Ok(vec![Variable::BOOL, var]);
|
||||
}
|
||||
loop {
|
||||
match subs.get_content_without_compacting(var) {
|
||||
|
@ -95,10 +136,8 @@ fn index_var(
|
|||
| Content::FlexAbleVar(_, _)
|
||||
| Content::RigidAbleVar(_, _)
|
||||
| Content::LambdaSet(_)
|
||||
| Content::RangedNumber(..) => internal_error!("not a indexable constructor"),
|
||||
Content::Error => {
|
||||
internal_error!("errors should not be reachable during exhautiveness checking")
|
||||
}
|
||||
| Content::RangedNumber(..) => return Err(TypeError),
|
||||
Content::Error => return Err(TypeError),
|
||||
Content::RecursionVar {
|
||||
structure,
|
||||
opt_name: _,
|
||||
|
@ -106,14 +145,19 @@ fn index_var(
|
|||
var = *structure;
|
||||
}
|
||||
Content::Structure(structure) => match structure {
|
||||
FlatType::Apply(_, _)
|
||||
| FlatType::Func(_, _, _)
|
||||
| FlatType::FunctionOrTagUnion(_, _, _) => {
|
||||
internal_error!("not an indexable constructor")
|
||||
FlatType::Func(_, _, _) | FlatType::FunctionOrTagUnion(_, _, _) => {
|
||||
return Err(TypeError)
|
||||
}
|
||||
FlatType::Erroneous(_) => {
|
||||
internal_error!("errors should not be reachable during exhautiveness checking")
|
||||
FlatType::Erroneous(_) => return Err(TypeError),
|
||||
FlatType::Apply(Symbol::LIST_LIST, args) => {
|
||||
match (subs.get_subs_slice(*args), ctor) {
|
||||
([elem_var], IndexCtor::List) => {
|
||||
return Ok(vec![*elem_var]);
|
||||
}
|
||||
_ => internal_error!("list types can only be indexed by list patterns"),
|
||||
}
|
||||
}
|
||||
FlatType::Apply(..) => internal_error!("not an indexable constructor"),
|
||||
FlatType::Record(fields, ext) => {
|
||||
let fields_order = match render_as {
|
||||
RenderAs::Record(fields) => fields,
|
||||
|
@ -137,7 +181,7 @@ fn index_var(
|
|||
})
|
||||
.collect();
|
||||
|
||||
return field_types;
|
||||
return Ok(field_types);
|
||||
}
|
||||
FlatType::TagUnion(tags, ext) | FlatType::RecursiveTagUnion(_, tags, ext) => {
|
||||
let tag_ctor = match ctor {
|
||||
|
@ -155,10 +199,10 @@ fn index_var(
|
|||
}
|
||||
});
|
||||
let vars = opt_vars.expect("constructor must be known in the indexable type if we are exhautiveness checking");
|
||||
return vars;
|
||||
return Ok(vars);
|
||||
}
|
||||
FlatType::EmptyRecord => {
|
||||
debug_assert!(matches!(ctor, IndexCtor::Record));
|
||||
debug_assert!(matches!(ctor, IndexCtor::Record(..)));
|
||||
// If there are optional record fields we don't unify them, but we need to
|
||||
// cover them. Since optional fields correspond to "any" patterns, we can pass
|
||||
// through arbitrary types.
|
||||
|
@ -168,7 +212,7 @@ fn index_var(
|
|||
"record constructors must always be rendered as records"
|
||||
),
|
||||
};
|
||||
return std::iter::repeat(Variable::NULL).take(num_fields).collect();
|
||||
return Ok(std::iter::repeat(Variable::NULL).take(num_fields).collect());
|
||||
}
|
||||
FlatType::EmptyTagUnion => {
|
||||
internal_error!("empty tag unions are not indexable")
|
||||
|
@ -176,7 +220,7 @@ fn index_var(
|
|||
},
|
||||
Content::Alias(_, _, var, AliasKind::Opaque) => {
|
||||
debug_assert!(matches!(ctor, IndexCtor::Opaque));
|
||||
return vec![*var];
|
||||
return Ok(vec![*var]);
|
||||
}
|
||||
Content::Alias(_, _, inner, AliasKind::Structural) => {
|
||||
var = *inner;
|
||||
|
@ -186,35 +230,44 @@ fn index_var(
|
|||
}
|
||||
|
||||
impl SketchedPattern {
|
||||
fn reify(self, subs: &Subs, real_var: Variable) -> Pattern {
|
||||
fn reify(self, subs: &Subs, real_var: Variable) -> Result<Pattern, TypeError> {
|
||||
match self {
|
||||
Self::Anything => Pattern::Anything,
|
||||
Self::Literal(lit) => Pattern::Literal(lit),
|
||||
Self::KnownCtor(union, index_ctor, tag_id, patterns) => {
|
||||
let arg_vars = index_var(subs, real_var, index_ctor, &union.render_as);
|
||||
Self::Anything => Ok(Pattern::Anything),
|
||||
Self::Literal(lit) => Ok(Pattern::Literal(lit)),
|
||||
Self::KnownCtor(union, tag_id, patterns) => {
|
||||
let index_ctor = IndexCtor::of_union(&union, tag_id);
|
||||
let arg_vars = index_var(subs, real_var, index_ctor, &union.render_as)?;
|
||||
|
||||
debug_assert!(arg_vars.len() == patterns.len());
|
||||
let args = (patterns.into_iter())
|
||||
.zip(arg_vars)
|
||||
.map(|(pat, var)| {
|
||||
// FIXME
|
||||
pat.reify(subs, var)
|
||||
})
|
||||
.collect();
|
||||
.map(|(pat, var)| pat.reify(subs, var))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
Pattern::Ctor(union, tag_id, args)
|
||||
Ok(Pattern::Ctor(union, tag_id, args))
|
||||
}
|
||||
Self::Ctor(tag_name, patterns) => {
|
||||
let arg_vars = index_var(subs, real_var, IndexCtor::Tag(&tag_name), &RenderAs::Tag);
|
||||
let arg_vars =
|
||||
index_var(subs, real_var, IndexCtor::Tag(&tag_name), &RenderAs::Tag)?;
|
||||
let (union, tag_id) = convert_tag(subs, real_var, &tag_name);
|
||||
|
||||
debug_assert!(arg_vars.len() == patterns.len());
|
||||
let args = (patterns.into_iter())
|
||||
.zip(arg_vars)
|
||||
.map(|(pat, var)| pat.reify(subs, var))
|
||||
.collect();
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
Pattern::Ctor(union, tag_id, args)
|
||||
Ok(Pattern::Ctor(union, tag_id, args))
|
||||
}
|
||||
Self::List(arity, patterns) => {
|
||||
let elem_var = index_var(subs, real_var, IndexCtor::List, &RenderAs::Tag)?[0];
|
||||
|
||||
let patterns = patterns
|
||||
.into_iter()
|
||||
.map(|pat| pat.reify(subs, elem_var))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
Ok(Pattern::List(arity, patterns))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -235,7 +288,11 @@ pub struct SketchedRows {
|
|||
}
|
||||
|
||||
impl SketchedRows {
|
||||
fn reify_to_non_redundant(self, subs: &Subs, real_var: Variable) -> NonRedundantSummary {
|
||||
fn reify_to_non_redundant(
|
||||
self,
|
||||
subs: &Subs,
|
||||
real_var: Variable,
|
||||
) -> Result<NonRedundantSummary, TypeError> {
|
||||
to_nonredundant_rows(subs, real_var, self)
|
||||
}
|
||||
}
|
||||
|
@ -283,7 +340,23 @@ fn sketch_pattern(pattern: &crate::pattern::Pattern) -> SketchedPattern {
|
|||
}],
|
||||
};
|
||||
|
||||
SP::KnownCtor(union, IndexCtor::Record, tag_id, patterns)
|
||||
SP::KnownCtor(union, tag_id, patterns)
|
||||
}
|
||||
|
||||
List {
|
||||
patterns,
|
||||
list_var: _,
|
||||
elem_var: _,
|
||||
} => {
|
||||
let arity = patterns.arity();
|
||||
|
||||
let sketched_elem_patterns = patterns
|
||||
.patterns
|
||||
.iter()
|
||||
.map(|p| sketch_pattern(&p.value))
|
||||
.collect();
|
||||
|
||||
SP::List(arity, sketched_elem_patterns)
|
||||
}
|
||||
|
||||
AppliedTag {
|
||||
|
@ -315,12 +388,7 @@ fn sketch_pattern(pattern: &crate::pattern::Pattern) -> SketchedPattern {
|
|||
}],
|
||||
};
|
||||
|
||||
SP::KnownCtor(
|
||||
union,
|
||||
IndexCtor::Opaque,
|
||||
tag_id,
|
||||
vec![sketch_pattern(&argument.value)],
|
||||
)
|
||||
SP::KnownCtor(union, tag_id, vec![sketch_pattern(&argument.value)])
|
||||
}
|
||||
|
||||
// Treat this like a literal so we mark it as non-exhaustive
|
||||
|
@ -390,7 +458,6 @@ pub fn sketch_when_branches(region: Region, patterns: &[expr::WhenBranch]) -> Sk
|
|||
|
||||
vec![SP::KnownCtor(
|
||||
union,
|
||||
IndexCtor::Guard,
|
||||
tag_id,
|
||||
// NB: ordering the guard pattern first seems to be better at catching
|
||||
// non-exhaustive constructors in the second argument; see the paper to see if
|
||||
|
@ -445,7 +512,7 @@ fn to_nonredundant_rows(
|
|||
subs: &Subs,
|
||||
real_var: Variable,
|
||||
rows: SketchedRows,
|
||||
) -> NonRedundantSummary {
|
||||
) -> Result<NonRedundantSummary, TypeError> {
|
||||
let SketchedRows {
|
||||
rows,
|
||||
overall_region,
|
||||
|
@ -468,7 +535,7 @@ fn to_nonredundant_rows(
|
|||
let next_row: Vec<Pattern> = patterns
|
||||
.into_iter()
|
||||
.map(|pattern| pattern.reify(subs, real_var))
|
||||
.collect();
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
let redundant_err = if !is_inhabited_row(&next_row) {
|
||||
Some(Error::Unmatchable {
|
||||
|
@ -499,11 +566,11 @@ fn to_nonredundant_rows(
|
|||
}
|
||||
}
|
||||
|
||||
NonRedundantSummary {
|
||||
Ok(NonRedundantSummary {
|
||||
non_redundant_rows: checked_rows,
|
||||
redundancies,
|
||||
errors,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn is_inhabited_row(patterns: &[Pattern]) -> bool {
|
||||
|
@ -518,10 +585,16 @@ fn is_inhabited_pattern(pat: &Pattern) -> bool {
|
|||
Pattern::Literal(_) => {}
|
||||
Pattern::Ctor(union, id, pats) => {
|
||||
if !union.alternatives.iter().any(|alt| alt.tag_id == *id) {
|
||||
// The tag ID was dropped from the union, which means that this tag ID is one
|
||||
// that is not material to the union, and so is uninhabited!
|
||||
return false;
|
||||
}
|
||||
stack.extend(pats);
|
||||
}
|
||||
Pattern::List(_, pats) => {
|
||||
// List is uninhabited if any element is uninhabited.
|
||||
stack.extend(pats);
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
|
|
|
@ -65,7 +65,7 @@ impl Output {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Copy)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Copy)]
|
||||
pub enum IntValue {
|
||||
I128([u8; 16]),
|
||||
U128([u8; 16]),
|
||||
|
@ -345,7 +345,7 @@ pub struct ClosureData {
|
|||
///
|
||||
/// We distinguish them from closures so we can have better error messages
|
||||
/// during constraint generation.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct AccessorData {
|
||||
pub name: Symbol,
|
||||
pub function_var: Variable,
|
||||
|
@ -485,7 +485,7 @@ pub struct Field {
|
|||
pub loc_expr: Box<Loc<Expr>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Recursive {
|
||||
NotRecursive = 0,
|
||||
Recursive = 1,
|
||||
|
@ -888,7 +888,7 @@ pub fn canonicalize_expr<'a>(
|
|||
var_store,
|
||||
inner_scope,
|
||||
region,
|
||||
*branch,
|
||||
branch,
|
||||
&mut output,
|
||||
)
|
||||
});
|
||||
|
@ -1493,7 +1493,7 @@ fn canonicalize_fields<'a>(
|
|||
let mut output = Output::default();
|
||||
|
||||
for loc_field in fields.iter() {
|
||||
match canonicalize_field(env, var_store, scope, &loc_field.value, loc_field.region) {
|
||||
match canonicalize_field(env, var_store, scope, &loc_field.value) {
|
||||
Ok((label, field_expr, field_out, field_var)) => {
|
||||
let field = Field {
|
||||
var: field_var,
|
||||
|
@ -1546,7 +1546,6 @@ fn canonicalize_field<'a>(
|
|||
var_store: &mut VarStore,
|
||||
scope: &mut Scope,
|
||||
field: &'a ast::AssignedField<'a, ast::Expr<'a>>,
|
||||
region: Region,
|
||||
) -> Result<(Lowercase, Loc<Expr>, Output, Variable), CanonicalizeFieldProblem> {
|
||||
use roc_parse::ast::AssignedField::*;
|
||||
|
||||
|
@ -1576,7 +1575,7 @@ fn canonicalize_field<'a>(
|
|||
}
|
||||
|
||||
SpaceBefore(sub_field, _) | SpaceAfter(sub_field, _) => {
|
||||
canonicalize_field(env, var_store, scope, sub_field, region)
|
||||
canonicalize_field(env, var_store, scope, sub_field)
|
||||
}
|
||||
|
||||
Malformed(_string) => {
|
||||
|
@ -1652,7 +1651,7 @@ fn canonicalize_var_lookup(
|
|||
}
|
||||
|
||||
/// Currently uses the heuristic of "only inline if it's a builtin"
|
||||
pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) -> Expr {
|
||||
pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
|
||||
use Expr::*;
|
||||
|
||||
match expr {
|
||||
|
@ -1681,7 +1680,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
|||
let mut new_elems = Vec::with_capacity(loc_elems.len());
|
||||
|
||||
for loc_elem in loc_elems {
|
||||
let value = inline_calls(var_store, scope, loc_elem.value);
|
||||
let value = inline_calls(var_store, loc_elem.value);
|
||||
|
||||
new_elems.push(Loc {
|
||||
value,
|
||||
|
@ -1706,20 +1705,20 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
|||
} => {
|
||||
let loc_cond = Box::new(Loc {
|
||||
region: loc_cond.region,
|
||||
value: inline_calls(var_store, scope, loc_cond.value),
|
||||
value: inline_calls(var_store, loc_cond.value),
|
||||
});
|
||||
|
||||
let mut new_branches = Vec::with_capacity(branches.len());
|
||||
|
||||
for branch in branches {
|
||||
let value = Loc {
|
||||
value: inline_calls(var_store, scope, branch.value.value),
|
||||
value: inline_calls(var_store, branch.value.value),
|
||||
region: branch.value.region,
|
||||
};
|
||||
let guard = match branch.guard {
|
||||
Some(loc_expr) => Some(Loc {
|
||||
region: loc_expr.region,
|
||||
value: inline_calls(var_store, scope, loc_expr.value),
|
||||
value: inline_calls(var_store, loc_expr.value),
|
||||
}),
|
||||
None => None,
|
||||
};
|
||||
|
@ -1753,12 +1752,12 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
|||
|
||||
for (loc_cond, loc_expr) in branches {
|
||||
let loc_cond = Loc {
|
||||
value: inline_calls(var_store, scope, loc_cond.value),
|
||||
value: inline_calls(var_store, loc_cond.value),
|
||||
region: loc_cond.region,
|
||||
};
|
||||
|
||||
let loc_expr = Loc {
|
||||
value: inline_calls(var_store, scope, loc_expr.value),
|
||||
value: inline_calls(var_store, loc_expr.value),
|
||||
region: loc_expr.region,
|
||||
};
|
||||
|
||||
|
@ -1767,7 +1766,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
|||
|
||||
let final_else = Box::new(Loc {
|
||||
region: final_else.region,
|
||||
value: inline_calls(var_store, scope, final_else.value),
|
||||
value: inline_calls(var_store, final_else.value),
|
||||
});
|
||||
|
||||
If {
|
||||
|
@ -1785,12 +1784,12 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
|||
} => {
|
||||
let loc_condition = Loc {
|
||||
region: loc_condition.region,
|
||||
value: inline_calls(var_store, scope, loc_condition.value),
|
||||
value: inline_calls(var_store, loc_condition.value),
|
||||
};
|
||||
|
||||
let loc_continuation = Loc {
|
||||
region: loc_continuation.region,
|
||||
value: inline_calls(var_store, scope, loc_continuation.value),
|
||||
value: inline_calls(var_store, loc_continuation.value),
|
||||
};
|
||||
|
||||
Expect {
|
||||
|
@ -1807,12 +1806,12 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
|||
} => {
|
||||
let loc_condition = Loc {
|
||||
region: loc_condition.region,
|
||||
value: inline_calls(var_store, scope, loc_condition.value),
|
||||
value: inline_calls(var_store, loc_condition.value),
|
||||
};
|
||||
|
||||
let loc_continuation = Loc {
|
||||
region: loc_continuation.region,
|
||||
value: inline_calls(var_store, scope, loc_continuation.value),
|
||||
value: inline_calls(var_store, loc_continuation.value),
|
||||
};
|
||||
|
||||
ExpectFx {
|
||||
|
@ -1830,7 +1829,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
|||
loc_pattern: def.loc_pattern,
|
||||
loc_expr: Loc {
|
||||
region: def.loc_expr.region,
|
||||
value: inline_calls(var_store, scope, def.loc_expr.value),
|
||||
value: inline_calls(var_store, def.loc_expr.value),
|
||||
},
|
||||
expr_var: def.expr_var,
|
||||
pattern_vars: def.pattern_vars,
|
||||
|
@ -1840,7 +1839,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
|||
|
||||
let loc_expr = Loc {
|
||||
region: loc_expr.region,
|
||||
value: inline_calls(var_store, scope, loc_expr.value),
|
||||
value: inline_calls(var_store, loc_expr.value),
|
||||
};
|
||||
|
||||
LetRec(new_defs, Box::new(loc_expr), mark)
|
||||
|
@ -1851,7 +1850,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
|||
loc_pattern: def.loc_pattern,
|
||||
loc_expr: Loc {
|
||||
region: def.loc_expr.region,
|
||||
value: inline_calls(var_store, scope, def.loc_expr.value),
|
||||
value: inline_calls(var_store, def.loc_expr.value),
|
||||
},
|
||||
expr_var: def.expr_var,
|
||||
pattern_vars: def.pattern_vars,
|
||||
|
@ -1860,7 +1859,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
|||
|
||||
let loc_expr = Loc {
|
||||
region: loc_expr.region,
|
||||
value: inline_calls(var_store, scope, loc_expr.value),
|
||||
value: inline_calls(var_store, loc_expr.value),
|
||||
};
|
||||
|
||||
LetNonRec(Box::new(def), Box::new(loc_expr))
|
||||
|
@ -1878,7 +1877,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
|||
}) => {
|
||||
let loc_expr = *loc_body;
|
||||
let loc_expr = Loc {
|
||||
value: inline_calls(var_store, scope, loc_expr.value),
|
||||
value: inline_calls(var_store, loc_expr.value),
|
||||
region: loc_expr.region,
|
||||
};
|
||||
|
||||
|
@ -1938,7 +1937,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
|||
let (var, loc_expr) = *argument;
|
||||
let argument = Box::new((
|
||||
var,
|
||||
loc_expr.map_owned(|expr| inline_calls(var_store, scope, expr)),
|
||||
loc_expr.map_owned(|expr| inline_calls(var_store, expr)),
|
||||
));
|
||||
|
||||
OpaqueRef {
|
||||
|
@ -2737,7 +2736,7 @@ fn get_lookup_symbols(expr: &Expr) -> Vec<ExpectLookup> {
|
|||
| Expr::ExpectFx {
|
||||
loc_continuation, ..
|
||||
} => {
|
||||
stack.push(&(*loc_continuation).value);
|
||||
stack.push(&loc_continuation.value);
|
||||
|
||||
// Intentionally ignore the lookups in the nested `expect` condition itself,
|
||||
// because they couldn't possibly influence the outcome of this `expect`!
|
||||
|
|
|
@ -898,6 +898,15 @@ fn fix_values_captured_in_closure_pattern(
|
|||
}
|
||||
}
|
||||
}
|
||||
List { patterns, .. } => {
|
||||
for loc_pat in patterns.patterns.iter_mut() {
|
||||
fix_values_captured_in_closure_pattern(
|
||||
&mut loc_pat.value,
|
||||
no_capture_symbols,
|
||||
closure_captures,
|
||||
);
|
||||
}
|
||||
}
|
||||
Identifier(_)
|
||||
| NumLiteral(..)
|
||||
| IntLiteral(..)
|
||||
|
|
|
@ -79,7 +79,7 @@ fn desugar_value_def<'a>(arena: &'a Bump, def: &'a ValueDef<'a>) -> ValueDef<'a>
|
|||
ann_pattern,
|
||||
ann_type,
|
||||
comment: *comment,
|
||||
body_pattern: *body_pattern,
|
||||
body_pattern,
|
||||
body_expr: desugar_expr(arena, body_expr),
|
||||
},
|
||||
Expect {
|
||||
|
|
|
@ -6,6 +6,7 @@ use crate::num::{
|
|||
ParsedNumResult,
|
||||
};
|
||||
use crate::scope::{PendingAbilitiesInScope, Scope};
|
||||
use roc_exhaustive::ListArity;
|
||||
use roc_module::ident::{Ident, Lowercase, TagName};
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_parse::ast::{self, StrLiteral, StrSegment};
|
||||
|
@ -56,6 +57,11 @@ pub enum Pattern {
|
|||
ext_var: Variable,
|
||||
destructs: Vec<Loc<RecordDestruct>>,
|
||||
},
|
||||
List {
|
||||
list_var: Variable,
|
||||
elem_var: Variable,
|
||||
patterns: ListPatterns,
|
||||
},
|
||||
NumLiteral(Variable, Box<str>, IntValue, NumBound),
|
||||
IntLiteral(Variable, Variable, Box<str>, IntValue, IntBound),
|
||||
FloatLiteral(Variable, Variable, Box<str>, f64, FloatBound),
|
||||
|
@ -92,6 +98,10 @@ impl Pattern {
|
|||
AppliedTag { whole_var, .. } => Some(*whole_var),
|
||||
UnwrappedOpaque { whole_var, .. } => Some(*whole_var),
|
||||
RecordDestructure { whole_var, .. } => Some(*whole_var),
|
||||
List {
|
||||
list_var: whole_var,
|
||||
..
|
||||
} => Some(*whole_var),
|
||||
NumLiteral(var, ..) => Some(*var),
|
||||
IntLiteral(var, ..) => Some(*var),
|
||||
FloatLiteral(var, ..) => Some(*var),
|
||||
|
@ -119,6 +129,7 @@ impl Pattern {
|
|||
| MalformedPattern(..)
|
||||
| AbilityMemberSpecialization { .. } => true,
|
||||
RecordDestructure { destructs, .. } => destructs.is_empty(),
|
||||
List { patterns, .. } => patterns.surely_exhaustive(),
|
||||
AppliedTag { .. }
|
||||
| NumLiteral(..)
|
||||
| IntLiteral(..)
|
||||
|
@ -145,6 +156,7 @@ impl Pattern {
|
|||
UnwrappedOpaque { opaque, .. } => C::Opaque(*opaque),
|
||||
RecordDestructure { destructs, .. } if destructs.is_empty() => C::EmptyRecord,
|
||||
RecordDestructure { .. } => C::Record,
|
||||
List { .. } => C::List,
|
||||
NumLiteral(..) => C::Num,
|
||||
IntLiteral(..) => C::Int,
|
||||
FloatLiteral(..) => C::Float,
|
||||
|
@ -161,6 +173,36 @@ impl Pattern {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ListPatterns {
|
||||
pub patterns: Vec<Loc<Pattern>>,
|
||||
/// Where a rest pattern splits patterns before and after it, if it does at all.
|
||||
/// If present, patterns at index >= the rest index appear after the rest pattern.
|
||||
/// For example:
|
||||
/// [ .., A, B ] -> patterns = [A, B], rest = 0
|
||||
/// [ A, .., B ] -> patterns = [A, B], rest = 1
|
||||
/// [ A, B, .. ] -> patterns = [A, B], rest = 2
|
||||
pub opt_rest: Option<usize>,
|
||||
}
|
||||
|
||||
impl ListPatterns {
|
||||
/// Is this list pattern the trivially-exhaustive pattern `[..]`?
|
||||
fn surely_exhaustive(&self) -> bool {
|
||||
self.patterns.is_empty() && matches!(self.opt_rest, Some(0))
|
||||
}
|
||||
|
||||
pub fn arity(&self) -> ListArity {
|
||||
match self.opt_rest {
|
||||
Some(i) => {
|
||||
let before = i;
|
||||
let after = self.patterns.len() - before;
|
||||
ListArity::Slice(before, after)
|
||||
}
|
||||
None => ListArity::Exact(self.patterns.len()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RecordDestruct {
|
||||
pub var: Variable,
|
||||
|
@ -621,8 +663,75 @@ pub fn canonicalize_pattern<'a>(
|
|||
unreachable!("should have been handled in RecordDestructure");
|
||||
}
|
||||
|
||||
List(..) => todo!(),
|
||||
ListRest => todo!(),
|
||||
List(patterns) => {
|
||||
// We want to admit the following cases:
|
||||
//
|
||||
// []
|
||||
// [..]
|
||||
// [.., P_1,* P_n]
|
||||
// [P_1,* P_n, ..]
|
||||
// [P_1,* P_m, .., P_n,* P_q]
|
||||
// [P_1,* P_n]
|
||||
//
|
||||
// So, a list-rest pattern can appear anywhere in a list pattern, but can appear at
|
||||
// most once.
|
||||
let elem_var = var_store.fresh();
|
||||
let list_var = var_store.fresh();
|
||||
|
||||
let mut rest_index = None;
|
||||
let mut can_pats = Vec::with_capacity(patterns.len());
|
||||
let mut opt_erroneous = None;
|
||||
|
||||
for (i, loc_pattern) in patterns.iter().enumerate() {
|
||||
match &loc_pattern.value {
|
||||
ListRest => match rest_index {
|
||||
None => {
|
||||
rest_index = Some(i);
|
||||
}
|
||||
Some(_) => {
|
||||
env.problem(Problem::MultipleListRestPattern {
|
||||
region: loc_pattern.region,
|
||||
});
|
||||
|
||||
opt_erroneous = Some(Pattern::MalformedPattern(
|
||||
MalformedPatternProblem::DuplicateListRestPattern,
|
||||
loc_pattern.region,
|
||||
));
|
||||
}
|
||||
},
|
||||
pattern => {
|
||||
let pat = canonicalize_pattern(
|
||||
env,
|
||||
var_store,
|
||||
scope,
|
||||
output,
|
||||
pattern_type,
|
||||
pattern,
|
||||
loc_pattern.region,
|
||||
permit_shadows,
|
||||
);
|
||||
can_pats.push(pat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we encountered an erroneous pattern (e.g. one with shadowing),
|
||||
// use the resulting RuntimeError. Otherwise, return a successful record destructure.
|
||||
opt_erroneous.unwrap_or(Pattern::List {
|
||||
list_var,
|
||||
elem_var,
|
||||
patterns: ListPatterns {
|
||||
patterns: can_pats,
|
||||
opt_rest: rest_index,
|
||||
},
|
||||
})
|
||||
}
|
||||
ListRest => {
|
||||
// Parsing should make sure these only appear in list patterns, where we will generate
|
||||
// better contextual errors.
|
||||
let problem = MalformedPatternProblem::Unknown;
|
||||
malformed_pattern(env, problem, region)
|
||||
}
|
||||
|
||||
Malformed(_str) => {
|
||||
let problem = MalformedPatternProblem::Unknown;
|
||||
|
@ -739,6 +848,9 @@ impl<'a> BindingsFromPattern<'a> {
|
|||
| MalformedPattern(_, _)
|
||||
| UnsupportedPattern(_)
|
||||
| OpaqueNotInScope(..) => (),
|
||||
List { patterns, .. } => {
|
||||
stack.extend(patterns.patterns.iter().rev().map(Pattern));
|
||||
}
|
||||
}
|
||||
}
|
||||
BindingsFromPatternWork::Destruct(loc_destruct) => {
|
||||
|
|
|
@ -472,6 +472,12 @@ pub fn walk_pattern<V: Visitor>(visitor: &mut V, pattern: &Pattern) {
|
|||
RecordDestructure { destructs, .. } => destructs
|
||||
.iter()
|
||||
.for_each(|d| visitor.visit_record_destruct(&d.value, d.region)),
|
||||
List {
|
||||
patterns, elem_var, ..
|
||||
} => patterns
|
||||
.patterns
|
||||
.iter()
|
||||
.for_each(|p| visitor.visit_pattern(&p.value, p.region, Some(*elem_var))),
|
||||
NumLiteral(..) => { /* terminal */ }
|
||||
IntLiteral(..) => { /* terminal */ }
|
||||
FloatLiteral(..) => { /* terminal */ }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{borrow::Borrow, iter::FromIterator};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct VecSet<T> {
|
||||
elements: Vec<T>,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use arrayvec::ArrayVec;
|
||||
use roc_can::constraint::{Constraint, Constraints};
|
||||
use roc_can::constraint::{Constraint, Constraints, TypeOrVar};
|
||||
use roc_can::expected::Expected::{self, *};
|
||||
use roc_can::num::{FloatBound, FloatWidth, IntBound, IntLitWidth, NumBound, SignDemand};
|
||||
use roc_module::symbol::Symbol;
|
||||
|
@ -30,7 +30,7 @@ pub fn add_numeric_bound_constr(
|
|||
num_num(Variable(num_var))
|
||||
}
|
||||
NumericBound::FloatExact(width) => {
|
||||
let actual_type = Variable(float_width_to_variable(width));
|
||||
let actual_type = constraints.push_type(Variable(float_width_to_variable(width)));
|
||||
let expected = Expected::ForReason(Reason::NumericLiteralSuffix, actual_type, region);
|
||||
let type_index = constraints.push_type(Variable(num_var));
|
||||
let expected_index = constraints.push_expected_type(expected);
|
||||
|
@ -42,7 +42,7 @@ pub fn add_numeric_bound_constr(
|
|||
Variable(num_var)
|
||||
}
|
||||
NumericBound::IntExact(width) => {
|
||||
let actual_type = Variable(int_lit_width_to_variable(width));
|
||||
let actual_type = constraints.push_type(Variable(int_lit_width_to_variable(width)));
|
||||
let expected = Expected::ForReason(Reason::NumericLiteralSuffix, actual_type, region);
|
||||
let type_index = constraints.push_type(Variable(num_var));
|
||||
let expected_index = constraints.push_expected_type(expected);
|
||||
|
@ -54,11 +54,10 @@ pub fn add_numeric_bound_constr(
|
|||
Variable(num_var)
|
||||
}
|
||||
NumericBound::Range(range) => {
|
||||
let actual_type = Variable(precision_var);
|
||||
let expected = Expected::NoExpectation(RangedNumber(range));
|
||||
let type_index = constraints.push_type(actual_type);
|
||||
let precision_type = constraints.push_type(Variable(precision_var));
|
||||
let expected = Expected::NoExpectation(constraints.push_type(RangedNumber(range)));
|
||||
let expected_index = constraints.push_expected_type(expected);
|
||||
let constr = constraints.equal_types(type_index, expected_index, category, region);
|
||||
let constr = constraints.equal_types(precision_type, expected_index, category, region);
|
||||
|
||||
num_constraints.extend([constr]);
|
||||
|
||||
|
@ -72,7 +71,7 @@ pub fn int_literal(
|
|||
constraints: &mut Constraints,
|
||||
num_var: Variable,
|
||||
precision_var: Variable,
|
||||
expected: Expected<Type>,
|
||||
expected: Expected<TypeOrVar>,
|
||||
region: Region,
|
||||
bound: IntBound,
|
||||
) -> Constraint {
|
||||
|
@ -91,11 +90,10 @@ pub fn int_literal(
|
|||
);
|
||||
|
||||
let num_type_index = constraints.push_type(num_type);
|
||||
let expect_precision_var = constraints.push_expected_type(ForReason(
|
||||
reason,
|
||||
num_int(Type::Variable(precision_var)),
|
||||
region,
|
||||
));
|
||||
let int_precision_type = constraints.push_type(num_int(Type::Variable(precision_var)));
|
||||
|
||||
let expect_precision_var =
|
||||
constraints.push_expected_type(ForReason(reason, int_precision_type, region));
|
||||
|
||||
constrs.extend([
|
||||
constraints.equal_types(num_type_index, expect_precision_var, Category::Int, region),
|
||||
|
@ -114,7 +112,7 @@ pub fn single_quote_literal(
|
|||
constraints: &mut Constraints,
|
||||
num_var: Variable,
|
||||
precision_var: Variable,
|
||||
expected: Expected<Type>,
|
||||
expected: Expected<TypeOrVar>,
|
||||
region: Region,
|
||||
bound: SingleQuoteBound,
|
||||
) -> Constraint {
|
||||
|
@ -133,11 +131,10 @@ pub fn single_quote_literal(
|
|||
);
|
||||
|
||||
let num_type_index = constraints.push_type(num_type);
|
||||
let expect_precision_var = constraints.push_expected_type(ForReason(
|
||||
reason,
|
||||
num_int(Type::Variable(precision_var)),
|
||||
region,
|
||||
));
|
||||
let int_precision_type = constraints.push_type(num_int(Type::Variable(precision_var)));
|
||||
|
||||
let expect_precision_var =
|
||||
constraints.push_expected_type(ForReason(reason, int_precision_type, region));
|
||||
|
||||
constrs.extend([
|
||||
constraints.equal_types(
|
||||
|
@ -161,7 +158,7 @@ pub fn float_literal(
|
|||
constraints: &mut Constraints,
|
||||
num_var: Variable,
|
||||
precision_var: Variable,
|
||||
expected: Expected<Type>,
|
||||
expected: Expected<TypeOrVar>,
|
||||
region: Region,
|
||||
bound: FloatBound,
|
||||
) -> Constraint {
|
||||
|
@ -179,11 +176,10 @@ pub fn float_literal(
|
|||
);
|
||||
|
||||
let num_type_index = constraints.push_type(num_type);
|
||||
let expect_precision_var = constraints.push_expected_type(ForReason(
|
||||
reason,
|
||||
num_float(Type::Variable(precision_var)),
|
||||
region,
|
||||
));
|
||||
let float_precision_type = constraints.push_type(num_float(Type::Variable(precision_var)));
|
||||
|
||||
let expect_precision_var =
|
||||
constraints.push_expected_type(ForReason(reason, float_precision_type, region));
|
||||
|
||||
constrs.extend([
|
||||
constraints.equal_types(num_type_index, expect_precision_var, Category::Frac, region),
|
||||
|
@ -201,7 +197,7 @@ pub fn float_literal(
|
|||
pub fn num_literal(
|
||||
constraints: &mut Constraints,
|
||||
num_var: Variable,
|
||||
expected: Expected<Type>,
|
||||
expected: Expected<TypeOrVar>,
|
||||
region: Region,
|
||||
bound: NumBound,
|
||||
) -> Constraint {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -50,8 +50,9 @@ fn constrain_symbols_from_requires(
|
|||
};
|
||||
let pattern = Loc::at_zero(roc_can::pattern::Pattern::Identifier(loc_symbol.value));
|
||||
|
||||
let type_index = constraints.push_type(loc_type.value);
|
||||
let def_pattern_state =
|
||||
constrain_def_pattern(constraints, &mut env, &pattern, loc_type.value);
|
||||
constrain_def_pattern(constraints, &mut env, &pattern, type_index);
|
||||
|
||||
debug_assert!(env.resolutions_to_make.is_empty());
|
||||
|
||||
|
@ -69,13 +70,15 @@ fn constrain_symbols_from_requires(
|
|||
// Otherwise, this symbol comes from an app module - we want to check that the type
|
||||
// provided by the app is in fact what the package module requires.
|
||||
let arity = loc_type.value.arity();
|
||||
let typ = loc_type.value;
|
||||
let type_index = constraints.push_type(typ);
|
||||
let expected = constraints.push_expected_type(Expected::FromAnnotation(
|
||||
loc_symbol.map(|&s| Pattern::Identifier(s)),
|
||||
arity,
|
||||
AnnotationSource::RequiredSymbol {
|
||||
region: loc_type.region,
|
||||
},
|
||||
loc_type.value,
|
||||
type_index,
|
||||
));
|
||||
let provided_eq_requires_constr =
|
||||
constraints.lookup(loc_symbol.value, expected, loc_type.region);
|
||||
|
@ -106,12 +109,10 @@ pub fn frontload_ability_constraints(
|
|||
};
|
||||
let pattern = Loc::at_zero(roc_can::pattern::Pattern::Identifier(*member_name));
|
||||
|
||||
let mut def_pattern_state = constrain_def_pattern(
|
||||
constraints,
|
||||
&mut env,
|
||||
&pattern,
|
||||
Type::Variable(signature_var),
|
||||
);
|
||||
let signature_index = constraints.push_type(signature.clone());
|
||||
|
||||
let mut def_pattern_state =
|
||||
constrain_def_pattern(constraints, &mut env, &pattern, signature_index);
|
||||
|
||||
debug_assert!(env.resolutions_to_make.is_empty());
|
||||
|
||||
|
@ -121,7 +122,7 @@ pub fn frontload_ability_constraints(
|
|||
let infer_variables = vars.flex_vars.iter().copied();
|
||||
|
||||
let signature_expectation =
|
||||
constraints.push_expected_type(Expected::NoExpectation(signature.clone()));
|
||||
constraints.push_expected_type(Expected::NoExpectation(signature_index));
|
||||
|
||||
def_pattern_state
|
||||
.constraints
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::builtins;
|
||||
use crate::expr::{constrain_expr, Env};
|
||||
use roc_can::constraint::{Constraint, Constraints};
|
||||
use roc_can::constraint::{Constraint, Constraints, TypeOrVar};
|
||||
use roc_can::expected::{Expected, PExpected};
|
||||
use roc_can::pattern::Pattern::{self, *};
|
||||
use roc_can::pattern::{DestructType, RecordDestruct};
|
||||
use roc_can::pattern::{DestructType, ListPatterns, RecordDestruct};
|
||||
use roc_collections::all::{HumanIndex, SendMap};
|
||||
use roc_collections::VecMap;
|
||||
use roc_module::ident::Lowercase;
|
||||
|
@ -17,7 +17,7 @@ use roc_types::types::{
|
|||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct PatternState {
|
||||
pub headers: VecMap<Symbol, Loc<Type>>,
|
||||
pub headers: VecMap<Symbol, Loc<TypeOrVar>>,
|
||||
pub vars: Vec<Variable>,
|
||||
pub constraints: Vec<Constraint>,
|
||||
pub delayed_is_open_constraints: Vec<Constraint>,
|
||||
|
@ -31,14 +31,16 @@ pub struct PatternState {
|
|||
/// Would add `x => <42>` to the headers (i.e., symbol points to a type variable). If the
|
||||
/// definition has an annotation, we instead now add `x => Int`.
|
||||
pub fn headers_from_annotation(
|
||||
constraints: &mut Constraints,
|
||||
pattern: &Pattern,
|
||||
annotation: &Loc<&Type>,
|
||||
) -> Option<VecMap<Symbol, Loc<Type>>> {
|
||||
) -> Option<VecMap<Symbol, Loc<TypeOrVar>>> {
|
||||
let mut headers = VecMap::default();
|
||||
// Check that the annotation structurally agrees with the pattern, preventing e.g. `{ x, y } : Int`
|
||||
// in such incorrect cases we don't put the full annotation in headers, just a variable, and let
|
||||
// inference generate a proper error.
|
||||
let is_structurally_valid = headers_from_annotation_help(pattern, annotation, &mut headers);
|
||||
let is_structurally_valid =
|
||||
headers_from_annotation_help(constraints, pattern, annotation, &mut headers);
|
||||
|
||||
if is_structurally_valid {
|
||||
Some(headers)
|
||||
|
@ -48,9 +50,10 @@ pub fn headers_from_annotation(
|
|||
}
|
||||
|
||||
fn headers_from_annotation_help(
|
||||
constraints: &mut Constraints,
|
||||
pattern: &Pattern,
|
||||
annotation: &Loc<&Type>,
|
||||
headers: &mut VecMap<Symbol, Loc<Type>>,
|
||||
headers: &mut VecMap<Symbol, Loc<TypeOrVar>>,
|
||||
) -> bool {
|
||||
match pattern {
|
||||
Identifier(symbol)
|
||||
|
@ -60,7 +63,8 @@ fn headers_from_annotation_help(
|
|||
ident: symbol,
|
||||
specializes: _,
|
||||
} => {
|
||||
let typ = Loc::at(annotation.region, annotation.value.clone());
|
||||
let annotation_index = constraints.push_type(annotation.value.clone());
|
||||
let typ = Loc::at(annotation.region, annotation_index);
|
||||
headers.insert(*symbol, typ);
|
||||
true
|
||||
}
|
||||
|
@ -87,9 +91,10 @@ fn headers_from_annotation_help(
|
|||
// `{ x ? 0 } = rec` or `{ x: 5 } -> ...` in all cases
|
||||
// the type of `x` within the binding itself is the same.
|
||||
if let Some(field_type) = fields.get(&destruct.label) {
|
||||
let field_type_index = constraints.push_type(field_type.as_inner().clone());
|
||||
headers.insert(
|
||||
destruct.symbol,
|
||||
Loc::at(annotation.region, field_type.clone().into_inner()),
|
||||
Loc::at(annotation.region, field_type_index),
|
||||
);
|
||||
} else {
|
||||
return false;
|
||||
|
@ -101,6 +106,14 @@ fn headers_from_annotation_help(
|
|||
_ => false,
|
||||
},
|
||||
|
||||
List { .. } => {
|
||||
// There are no interesting headers to introduce for list patterns, since the only
|
||||
// exhaustive list pattern is
|
||||
// \[..] -> <body>
|
||||
// which does not introduce any symbols.
|
||||
false
|
||||
},
|
||||
|
||||
AppliedTag {
|
||||
tag_name,
|
||||
arguments,
|
||||
|
@ -117,6 +130,7 @@ fn headers_from_annotation_help(
|
|||
.zip(arg_types.iter())
|
||||
.all(|(arg_pattern, arg_type)| {
|
||||
headers_from_annotation_help(
|
||||
constraints,
|
||||
&arg_pattern.1.value,
|
||||
&Loc::at(annotation.region, arg_type),
|
||||
headers,
|
||||
|
@ -148,11 +162,13 @@ fn headers_from_annotation_help(
|
|||
&& type_arguments.len() == pat_type_arguments.len()
|
||||
&& lambda_set_variables.len() == pat_lambda_set_variables.len() =>
|
||||
{
|
||||
let typ = Loc::at(annotation.region, annotation.value.clone());
|
||||
let annotation_index = constraints.push_type(annotation.value.clone());
|
||||
let typ = Loc::at(annotation.region, annotation_index);
|
||||
headers.insert(*opaque, typ);
|
||||
|
||||
let (_, argument_pat) = &**argument;
|
||||
headers_from_annotation_help(
|
||||
constraints,
|
||||
&argument_pat.value,
|
||||
&Loc::at(annotation.region, actual),
|
||||
headers,
|
||||
|
@ -171,7 +187,7 @@ pub fn constrain_pattern(
|
|||
env: &mut Env,
|
||||
pattern: &Pattern,
|
||||
region: Region,
|
||||
expected: PExpected<Type>,
|
||||
expected: PExpected<TypeOrVar>,
|
||||
state: &mut PatternState,
|
||||
) {
|
||||
match pattern {
|
||||
|
@ -182,8 +198,8 @@ pub fn constrain_pattern(
|
|||
// A -> ""
|
||||
// _ -> ""
|
||||
// so, we know that "x" (in this case, a tag union) must be open.
|
||||
if could_be_a_tag_union(expected.get_type_ref()) {
|
||||
let type_index = constraints.push_type(expected.get_type());
|
||||
if could_be_a_tag_union(constraints, *expected.get_type_ref()) {
|
||||
let type_index = expected.get_type();
|
||||
|
||||
state
|
||||
.delayed_is_open_constraints
|
||||
|
@ -195,9 +211,9 @@ pub fn constrain_pattern(
|
|||
}
|
||||
|
||||
Identifier(symbol) | Shadowed(_, _, symbol) => {
|
||||
if could_be_a_tag_union(expected.get_type_ref()) {
|
||||
let type_index = constraints.push_type(expected.get_type_ref().clone());
|
||||
let type_index = *expected.get_type_ref();
|
||||
|
||||
if could_be_a_tag_union(constraints, type_index) {
|
||||
state
|
||||
.delayed_is_open_constraints
|
||||
.push(constraints.is_open_type(type_index));
|
||||
|
@ -207,7 +223,7 @@ pub fn constrain_pattern(
|
|||
*symbol,
|
||||
Loc {
|
||||
region,
|
||||
value: expected.get_type(),
|
||||
value: type_index,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -216,9 +232,9 @@ pub fn constrain_pattern(
|
|||
ident: symbol,
|
||||
specializes: _,
|
||||
} => {
|
||||
if could_be_a_tag_union(expected.get_type_ref()) {
|
||||
let type_index = constraints.push_type(expected.get_type_ref().clone());
|
||||
let type_index = *expected.get_type_ref();
|
||||
|
||||
if could_be_a_tag_union(constraints, type_index) {
|
||||
state.constraints.push(constraints.is_open_type(type_index));
|
||||
}
|
||||
|
||||
|
@ -226,7 +242,7 @@ pub fn constrain_pattern(
|
|||
*symbol,
|
||||
Loc {
|
||||
region,
|
||||
value: expected.get_type(),
|
||||
value: type_index,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -270,7 +286,7 @@ pub fn constrain_pattern(
|
|||
let num_type = constraints.push_type(num_type);
|
||||
|
||||
// Link the free num var with the int var and our expectation.
|
||||
let int_type = builtins::num_int(Type::Variable(precision_var));
|
||||
let int_type = constraints.push_type(builtins::num_int(Type::Variable(precision_var)));
|
||||
|
||||
state.constraints.push({
|
||||
let expected_index =
|
||||
|
@ -300,10 +316,11 @@ pub fn constrain_pattern(
|
|||
region,
|
||||
Category::Frac,
|
||||
);
|
||||
let num_type_index = constraints.push_type(num_type); // TODO check me if something breaks!
|
||||
|
||||
// Link the free num var with the float var and our expectation.
|
||||
let float_type = builtins::num_float(Type::Variable(precision_var));
|
||||
let num_type_index = constraints.push_type(num_type); // TODO check me if something breaks!
|
||||
let float_type =
|
||||
constraints.push_type(builtins::num_float(Type::Variable(precision_var)));
|
||||
|
||||
state.constraints.push({
|
||||
let expected_index =
|
||||
|
@ -345,11 +362,11 @@ pub fn constrain_pattern(
|
|||
Category::Int,
|
||||
);
|
||||
|
||||
// Link the free num var with the int var and our expectation.
|
||||
let int_type = builtins::num_int(Type::Variable(precision_var));
|
||||
|
||||
let num_type_index = constraints.push_type(num_type);
|
||||
|
||||
// Link the free num var with the int var and our expectation.
|
||||
let int_type = constraints.push_type(builtins::num_int(Type::Variable(precision_var)));
|
||||
|
||||
state.constraints.push({
|
||||
let expected_index =
|
||||
constraints.push_expected_type(Expected::NoExpectation(int_type));
|
||||
|
@ -394,12 +411,13 @@ pub fn constrain_pattern(
|
|||
} in destructs
|
||||
{
|
||||
let pat_type = Type::Variable(*var);
|
||||
let expected = PExpected::NoExpectation(pat_type.clone());
|
||||
let pat_type_index = constraints.push_type(pat_type.clone());
|
||||
let expected = PExpected::NoExpectation(pat_type_index);
|
||||
|
||||
if !state.headers.contains_key(symbol) {
|
||||
state
|
||||
.headers
|
||||
.insert(*symbol, Loc::at(region, pat_type.clone()));
|
||||
.insert(*symbol, Loc::at(region, pat_type_index));
|
||||
}
|
||||
|
||||
let field_type = match typ {
|
||||
|
@ -408,7 +426,7 @@ pub fn constrain_pattern(
|
|||
let expected_pat =
|
||||
constraints.push_pat_expected_type(PExpected::ForReason(
|
||||
PReason::PatternGuard,
|
||||
pat_type.clone(),
|
||||
pat_type_index,
|
||||
loc_guard.region,
|
||||
));
|
||||
|
||||
|
@ -436,7 +454,7 @@ pub fn constrain_pattern(
|
|||
let expected_pat =
|
||||
constraints.push_pat_expected_type(PExpected::ForReason(
|
||||
PReason::OptionalField,
|
||||
pat_type.clone(),
|
||||
pat_type_index,
|
||||
loc_expr.region,
|
||||
));
|
||||
|
||||
|
@ -451,7 +469,7 @@ pub fn constrain_pattern(
|
|||
|
||||
let expr_expected = Expected::ForReason(
|
||||
Reason::RecordDefaultField(label.clone()),
|
||||
pat_type.clone(),
|
||||
pat_type_index,
|
||||
loc_expr.region,
|
||||
);
|
||||
|
||||
|
@ -477,7 +495,10 @@ pub fn constrain_pattern(
|
|||
state.vars.push(*var);
|
||||
}
|
||||
|
||||
let record_type = Type::Record(field_types, TypeExtension::from_type(ext_type));
|
||||
let record_type = constraints.push_type(Type::Record(
|
||||
field_types,
|
||||
TypeExtension::from_type(ext_type),
|
||||
));
|
||||
|
||||
let whole_var_index = constraints.push_type(Type::Variable(*whole_var));
|
||||
let expected_record =
|
||||
|
@ -501,6 +522,54 @@ pub fn constrain_pattern(
|
|||
state.constraints.push(whole_con);
|
||||
state.constraints.push(record_con);
|
||||
}
|
||||
|
||||
List {
|
||||
list_var,
|
||||
elem_var,
|
||||
patterns:
|
||||
ListPatterns {
|
||||
patterns,
|
||||
opt_rest: _,
|
||||
},
|
||||
} => {
|
||||
let elem_var_index = constraints.push_type(Type::Variable(*elem_var));
|
||||
|
||||
for loc_pat in patterns.iter() {
|
||||
let expected =
|
||||
PExpected::ForReason(PReason::ListElem, elem_var_index, loc_pat.region);
|
||||
|
||||
constrain_pattern(
|
||||
constraints,
|
||||
env,
|
||||
&loc_pat.value,
|
||||
loc_pat.region,
|
||||
expected,
|
||||
state,
|
||||
);
|
||||
}
|
||||
|
||||
let list_var_index = constraints.push_type(Type::Variable(*list_var));
|
||||
let solved_list = constraints.push_type(Type::Apply(
|
||||
Symbol::LIST_LIST,
|
||||
vec![Loc::at(region, Type::Variable(*elem_var))],
|
||||
region,
|
||||
));
|
||||
let store_solved_list = constraints.store(solved_list, *list_var, file!(), line!());
|
||||
|
||||
let expected = constraints.push_pat_expected_type(expected);
|
||||
let expected_constraint = constraints.pattern_presence(
|
||||
list_var_index,
|
||||
expected,
|
||||
PatternCategory::List,
|
||||
region,
|
||||
);
|
||||
|
||||
state.vars.push(*list_var);
|
||||
state.vars.push(*elem_var);
|
||||
state.constraints.push(store_solved_list);
|
||||
state.constraints.push(expected_constraint);
|
||||
}
|
||||
|
||||
AppliedTag {
|
||||
whole_var,
|
||||
ext_var,
|
||||
|
@ -512,7 +581,7 @@ pub fn constrain_pattern(
|
|||
for (index, (pattern_var, loc_pattern)) in arguments.iter().enumerate() {
|
||||
state.vars.push(*pattern_var);
|
||||
|
||||
let pattern_type = Type::Variable(*pattern_var);
|
||||
let pattern_type = constraints.push_type(Type::Variable(*pattern_var));
|
||||
|
||||
let expected = PExpected::ForReason(
|
||||
PReason::TagArg {
|
||||
|
@ -533,7 +602,7 @@ pub fn constrain_pattern(
|
|||
}
|
||||
|
||||
let pat_category = PatternCategory::Ctor(tag_name.clone());
|
||||
let expected_type = constraints.push_type(expected.get_type_ref().clone());
|
||||
let expected_type = *expected.get_type_ref();
|
||||
|
||||
let whole_con = constraints.includes_tag(
|
||||
expected_type,
|
||||
|
@ -565,8 +634,9 @@ pub fn constrain_pattern(
|
|||
// Suppose we are constraining the pattern \@Id who, where Id n := [Id U64 n]
|
||||
let (arg_pattern_var, loc_arg_pattern) = &**argument;
|
||||
let arg_pattern_type = Type::Variable(*arg_pattern_var);
|
||||
let arg_pattern_type_index = constraints.push_type(Type::Variable(*arg_pattern_var));
|
||||
|
||||
let opaque_type = Type::Alias {
|
||||
let opaque_type = constraints.push_type(Type::Alias {
|
||||
symbol: *opaque,
|
||||
type_arguments: type_arguments
|
||||
.iter()
|
||||
|
@ -579,10 +649,10 @@ pub fn constrain_pattern(
|
|||
infer_ext_in_output_types: vec![],
|
||||
actual: Box::new(arg_pattern_type.clone()),
|
||||
kind: AliasKind::Opaque,
|
||||
};
|
||||
});
|
||||
|
||||
// First, add a constraint for the argument "who"
|
||||
let arg_pattern_expected = PExpected::NoExpectation(arg_pattern_type.clone());
|
||||
let arg_pattern_expected = PExpected::NoExpectation(arg_pattern_type_index);
|
||||
constrain_pattern(
|
||||
constraints,
|
||||
env,
|
||||
|
@ -617,11 +687,13 @@ pub fn constrain_pattern(
|
|||
// `[A k1, B k1] += typeof (A s)`, because we are in a destructure position and not
|
||||
// all constructors are covered in this branch!
|
||||
let arg_pattern_type = constraints.push_type(arg_pattern_type);
|
||||
let specialized_type = constraints
|
||||
.push_pat_expected_type(PExpected::NoExpectation((**specialized_def_type).clone()));
|
||||
let specialized_type_index = constraints.push_type((**specialized_def_type).clone());
|
||||
let specialized_type_expected = constraints
|
||||
.push_pat_expected_type(PExpected::NoExpectation(specialized_type_index));
|
||||
|
||||
let link_type_variables_con = constraints.pattern_presence(
|
||||
arg_pattern_type,
|
||||
specialized_type,
|
||||
specialized_type_expected,
|
||||
PatternCategory::Opaque(*opaque),
|
||||
loc_arg_pattern.region,
|
||||
);
|
||||
|
@ -654,6 +726,18 @@ pub fn constrain_pattern(
|
|||
}
|
||||
}
|
||||
|
||||
fn could_be_a_tag_union(typ: &Type) -> bool {
|
||||
!matches!(typ, Type::Apply(..) | Type::Function(..) | Type::Record(..))
|
||||
fn could_be_a_tag_union(constraints: &mut Constraints, typ: TypeOrVar) -> bool {
|
||||
match typ.split() {
|
||||
Ok(typ_index) => {
|
||||
let typ_cell = &mut constraints.types[typ_index.index()];
|
||||
!matches!(
|
||||
typ_cell.get_mut(),
|
||||
Type::Apply(..) | Type::Function(..) | Type::Record(..)
|
||||
)
|
||||
}
|
||||
Err(_) => {
|
||||
// Variables are opaque at this point, assume yes
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,14 +99,11 @@ impl DerivedModule {
|
|||
exposed_by_module: &ExposedByModule,
|
||||
key: DeriveKey,
|
||||
) -> &(Symbol, Def, SpecializationLambdaSets) {
|
||||
match self.map.get(&key) {
|
||||
Some(entry) => {
|
||||
// rustc won't let us return an immutable reference *and* continue using
|
||||
// `self.map` immutably below, but this is safe, because we are not returning
|
||||
// an immutable reference to the entry.
|
||||
return unsafe { std::mem::transmute(entry) };
|
||||
}
|
||||
None => {}
|
||||
if let Some(entry) = self.map.get(&key) {
|
||||
// rustc won't let us return an immutable reference *and* continue using
|
||||
// `self.map` immutably below, but this is safe, because we are not returning
|
||||
// an immutable reference to the entry.
|
||||
return unsafe { std::mem::transmute(entry) };
|
||||
}
|
||||
|
||||
let ident_id = if cfg!(debug_assertions) || cfg!(feature = "debug-derived-symbols") {
|
||||
|
|
|
@ -25,7 +25,7 @@ use hash::{FlatHash, FlatHashKey};
|
|||
use roc_module::symbol::Symbol;
|
||||
use roc_types::subs::{Subs, Variable};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum DeriveError {
|
||||
/// Unbound variable present in the type-to-derive. It may be possible to derive for this type
|
||||
/// once the unbound variable is resolved.
|
||||
|
|
|
@ -9,3 +9,4 @@ edition = "2021"
|
|||
roc_collections = { path = "../collections" }
|
||||
roc_region = { path = "../region" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_error_macros = { path = "../../error_macros" }
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
//! http://moscova.inria.fr/~maranget/papers/warn/warn.pdf
|
||||
|
||||
use roc_collections::all::{HumanIndex, MutMap};
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::{
|
||||
ident::{Lowercase, TagIdIntType, TagName},
|
||||
symbol::Symbol,
|
||||
|
@ -69,6 +70,54 @@ pub enum Pattern {
|
|||
Anything,
|
||||
Literal(Literal),
|
||||
Ctor(Union, TagId, std::vec::Vec<Pattern>),
|
||||
List(ListArity, std::vec::Vec<Pattern>),
|
||||
}
|
||||
|
||||
/// The arity of list pattern.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum ListArity {
|
||||
/// A list pattern of an exact size.
|
||||
Exact(usize),
|
||||
/// A list pattern matching a variable size, where `Slice(before, after)` refers to the number
|
||||
/// of elements that must be present before and after the variable rest pattern, respectively.
|
||||
///
|
||||
/// For example,
|
||||
/// [..] => Slice(0, 0)
|
||||
/// [A, .., B] => Slice(1, 1)
|
||||
/// [A, B, ..] => Slice(2, 0)
|
||||
/// [.., A, B] => Slice(0, 2)
|
||||
Slice(usize, usize),
|
||||
}
|
||||
|
||||
impl ListArity {
|
||||
/// The trivially-exhaustive list pattern `[..]`
|
||||
const ANY: ListArity = ListArity::Slice(0, 0);
|
||||
|
||||
pub fn min_len(&self) -> usize {
|
||||
match self {
|
||||
ListArity::Exact(n) => *n,
|
||||
ListArity::Slice(l, r) => l + r,
|
||||
}
|
||||
}
|
||||
|
||||
/// Could this list pattern include list pattern arity `other`?
|
||||
fn covers_arities_of(&self, other: &Self) -> bool {
|
||||
self.covers_length(other.min_len())
|
||||
}
|
||||
|
||||
pub fn covers_length(&self, length: usize) -> bool {
|
||||
match self {
|
||||
ListArity::Exact(l) => {
|
||||
// [_, _, _] can only cover [_, _, _]
|
||||
*l == length
|
||||
}
|
||||
ListArity::Slice(head, tail) => {
|
||||
// [_, _, .., _] can cover infinite arities >=3 , including
|
||||
// [_, _, .., _], [_, .., _, _], [_, _, .., _, _], [_, _, _, .., _, _], and so on
|
||||
head + tail <= length
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -141,15 +190,16 @@ pub fn check(
|
|||
/// The initial count of items per row "n" is also 1
|
||||
/// The resulting rows are examples of missing patterns
|
||||
fn is_exhaustive(matrix: &RefPatternMatrix, n: usize) -> PatternMatrix {
|
||||
if matrix.is_empty() {
|
||||
vec![std::iter::repeat(Anything).take(n).collect()]
|
||||
let ctors = if matrix.is_empty() {
|
||||
return vec![std::iter::repeat(Anything).take(n).collect()];
|
||||
} else if n == 0 {
|
||||
vec![]
|
||||
return vec![];
|
||||
} else {
|
||||
let ctors = collect_ctors(matrix);
|
||||
let num_seen = ctors.len();
|
||||
collect_ctors(matrix)
|
||||
};
|
||||
|
||||
if num_seen == 0 {
|
||||
match ctors {
|
||||
CollectedCtors::NonExhaustiveAny => {
|
||||
let new_matrix: Vec<_> = matrix
|
||||
.iter()
|
||||
.filter_map(|row| specialize_row_by_anything(row))
|
||||
|
@ -161,7 +211,11 @@ fn is_exhaustive(matrix: &RefPatternMatrix, n: usize) -> PatternMatrix {
|
|||
}
|
||||
|
||||
rest
|
||||
} else {
|
||||
}
|
||||
CollectedCtors::Ctors(ctors) => {
|
||||
debug_assert!(!ctors.is_empty());
|
||||
|
||||
let num_seen = ctors.len();
|
||||
let alts = ctors.iter().next().unwrap().1;
|
||||
|
||||
let alt_list = &alts.alternatives;
|
||||
|
@ -193,7 +247,7 @@ fn is_exhaustive(matrix: &RefPatternMatrix, n: usize) -> PatternMatrix {
|
|||
let is_alt_exhaustive = |Ctor { arity, tag_id, .. }| {
|
||||
let new_matrix: Vec<_> = matrix
|
||||
.iter()
|
||||
.filter_map(|r| specialize_row_by_ctor(tag_id, arity, r))
|
||||
.filter_map(|r| specialize_row_by_ctor(tag_id, arity, r.to_owned()))
|
||||
.collect();
|
||||
let rest: Vec<Vec<Pattern>> = is_exhaustive(&new_matrix, arity + n - 1);
|
||||
|
||||
|
@ -212,6 +266,21 @@ fn is_exhaustive(matrix: &RefPatternMatrix, n: usize) -> PatternMatrix {
|
|||
.collect()
|
||||
}
|
||||
}
|
||||
CollectedCtors::NonExhaustiveList(alt_lists) => {
|
||||
let is_alt_exhaustive = |arity: ListArity| {
|
||||
let new_matrix: Vec<_> = matrix
|
||||
.iter()
|
||||
.filter_map(|row| specialize_row_by_list(arity, row.to_owned()))
|
||||
.collect();
|
||||
|
||||
let rest = is_exhaustive(&new_matrix, arity.min_len() + n - 1);
|
||||
|
||||
rest.into_iter()
|
||||
.map(move |row_not_covered| recover_list(arity, row_not_covered))
|
||||
};
|
||||
|
||||
alt_lists.into_iter().flat_map(is_alt_exhaustive).collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,14 +301,23 @@ fn recover_ctor(
|
|||
arity: usize,
|
||||
mut patterns: Vec<Pattern>,
|
||||
) -> Vec<Pattern> {
|
||||
let mut rest = patterns.split_off(arity);
|
||||
let args = patterns;
|
||||
let args = patterns.split_off(patterns.len() - arity);
|
||||
let mut rest = patterns;
|
||||
|
||||
rest.push(Ctor(union, tag_id, args));
|
||||
|
||||
rest
|
||||
}
|
||||
|
||||
fn recover_list(arity: ListArity, mut patterns: Vec<Pattern>) -> Vec<Pattern> {
|
||||
let list_elems = patterns.split_off(patterns.len() - arity.min_len());
|
||||
let mut rest = patterns;
|
||||
|
||||
rest.push(List(arity, list_elems));
|
||||
|
||||
rest
|
||||
}
|
||||
|
||||
/// Check if a new row "vector" is useful given previous rows "matrix"
|
||||
pub fn is_useful(mut old_matrix: PatternMatrix, mut vector: Row) -> bool {
|
||||
let mut matrix = Vec::with_capacity(old_matrix.len());
|
||||
|
@ -262,13 +340,53 @@ pub fn is_useful(mut old_matrix: PatternMatrix, mut vector: Row) -> bool {
|
|||
match first_pattern {
|
||||
// keep checking rows that start with this Ctor or Anything
|
||||
Ctor(_, id, args) => {
|
||||
specialize_row_by_ctor2(id, args.len(), &mut old_matrix, &mut matrix);
|
||||
specialize_matrix_by_ctor(id, args.len(), &mut old_matrix, &mut matrix);
|
||||
|
||||
std::mem::swap(&mut old_matrix, &mut matrix);
|
||||
|
||||
vector.extend(args);
|
||||
}
|
||||
|
||||
List(arity, args) => {
|
||||
// Check if there any specialized constructor of this list pattern
|
||||
// that is useful.
|
||||
let spec_list_ctors = build_list_ctors_covering_patterns(
|
||||
arity,
|
||||
filter_matrix_list_ctors(&old_matrix),
|
||||
);
|
||||
debug_assert!(!spec_list_ctors.is_empty());
|
||||
|
||||
if spec_list_ctors.len() == 1 {
|
||||
specialize_matrix_by_list(
|
||||
spec_list_ctors[0],
|
||||
&mut old_matrix,
|
||||
&mut matrix,
|
||||
);
|
||||
|
||||
std::mem::swap(&mut old_matrix, &mut matrix);
|
||||
|
||||
vector.extend(args);
|
||||
} else {
|
||||
// TODO turn this into an iteration over the outer loop rather than bouncing
|
||||
vector.extend(args);
|
||||
for list_ctor in spec_list_ctors {
|
||||
let mut old_matrix = old_matrix.clone();
|
||||
let mut spec_matrix = Vec::with_capacity(old_matrix.len());
|
||||
|
||||
specialize_matrix_by_list(
|
||||
list_ctor,
|
||||
&mut old_matrix,
|
||||
&mut spec_matrix,
|
||||
);
|
||||
|
||||
if is_useful(spec_matrix, vector.clone()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Anything => {
|
||||
// check if all alternatives appear in matrix
|
||||
match is_complete(&old_matrix) {
|
||||
|
@ -293,7 +411,7 @@ pub fn is_useful(mut old_matrix: PatternMatrix, mut vector: Row) -> bool {
|
|||
|
||||
let mut old_matrix = old_matrix.clone();
|
||||
let mut matrix = vec![];
|
||||
specialize_row_by_ctor2(
|
||||
specialize_matrix_by_ctor(
|
||||
tag_id,
|
||||
arity,
|
||||
&mut old_matrix,
|
||||
|
@ -330,6 +448,8 @@ pub fn is_useful(mut old_matrix: PatternMatrix, mut vector: Row) -> bool {
|
|||
}
|
||||
Some(Anything) => matrix.push(patterns),
|
||||
|
||||
Some(List(..)) => internal_error!("After type checking, lists and literals should never align in exhaustiveness checking"),
|
||||
|
||||
Some(Ctor(_, _, _)) => panic!(
|
||||
r#"Compiler bug! After type checking, constructors and literals should never align in pattern match exhaustiveness checks."#
|
||||
),
|
||||
|
@ -347,67 +467,118 @@ pub fn is_useful(mut old_matrix: PatternMatrix, mut vector: Row) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
/// INVARIANT: (length row == N) ==> (length result == arity + N - 1)
|
||||
fn specialize_row_by_ctor2(
|
||||
tag_id: TagId,
|
||||
arity: usize,
|
||||
// Specialize rows in the matrix that match a list's constructor(s).
|
||||
//
|
||||
// See the docs on [build_list_ctors_covering_patterns] for more information on how list
|
||||
// constructors are built up.
|
||||
fn specialize_matrix_by_list(
|
||||
spec_arity: ListArity,
|
||||
old_matrix: &mut PatternMatrix,
|
||||
matrix: &mut PatternMatrix,
|
||||
spec_matrix: &mut PatternMatrix,
|
||||
) {
|
||||
for mut row in old_matrix.drain(..) {
|
||||
let head = row.pop();
|
||||
let mut patterns = row;
|
||||
|
||||
match head {
|
||||
Some(Ctor(_, id, args)) =>
|
||||
if id == tag_id {
|
||||
patterns.extend(args);
|
||||
matrix.push(patterns);
|
||||
} else {
|
||||
// do nothing
|
||||
}
|
||||
Some(Anything) => {
|
||||
// TODO order!
|
||||
patterns.extend(std::iter::repeat(Anything).take(arity));
|
||||
matrix.push(patterns);
|
||||
}
|
||||
Some(Literal(_)) => panic!( "Compiler bug! After type checking, constructors and literal should never align in pattern match exhaustiveness checks."),
|
||||
None => panic!("Compiler error! Empty matrices should not get specialized."),
|
||||
}
|
||||
for row in old_matrix.drain(..) {
|
||||
if let Some(spec_row) = specialize_row_by_list(spec_arity, row) {
|
||||
spec_matrix.push(spec_row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// INVARIANT: (length row == N) ==> (length result == arity + N - 1)
|
||||
fn specialize_row_by_ctor(tag_id: TagId, arity: usize, row: &RefRow) -> Option<Row> {
|
||||
let mut row = row.to_vec();
|
||||
|
||||
// Specialize a row that matches a list's constructor(s).
|
||||
//
|
||||
// See the docs on [build_list_ctors_covering_patterns] for more information on how list
|
||||
// constructors are built up.
|
||||
fn specialize_row_by_list(spec_arity: ListArity, mut row: Row) -> Option<Row> {
|
||||
let head = row.pop();
|
||||
let patterns = row;
|
||||
let mut spec_patterns = row;
|
||||
|
||||
match head {
|
||||
Some(Ctor(_, id, args)) => {
|
||||
if id == tag_id {
|
||||
// TODO order!
|
||||
let mut new_patterns = Vec::new();
|
||||
new_patterns.extend(args);
|
||||
new_patterns.extend(patterns);
|
||||
Some(new_patterns)
|
||||
Some(List(this_arity, args)) => {
|
||||
if this_arity.covers_arities_of(&spec_arity) {
|
||||
// This pattern covers the constructor we are specializing, so add on the
|
||||
// specialized fields of this pattern relative to the given constructor.
|
||||
if spec_arity.min_len() != this_arity.min_len() {
|
||||
// This list pattern covers the list we are specializing, so it must be
|
||||
// a variable-length slice, i.e. of the form `[before, .., after]`.
|
||||
//
|
||||
// Hence, the list we're specializing for must have at least a larger minimum length.
|
||||
// So we fill the middle part with enough wildcards to reach the length of
|
||||
// list constructor we're specializing for.
|
||||
debug_assert!(spec_arity.min_len() > this_arity.min_len());
|
||||
match this_arity {
|
||||
ListArity::Exact(_) => internal_error!("exact-sized lists cannot cover lists of other minimum length"),
|
||||
ListArity::Slice(before, after) => {
|
||||
let before = &args[..before];
|
||||
let after = &args[this_arity.min_len() - after..];
|
||||
let num_extra_wildcards = spec_arity.min_len() - this_arity.min_len();
|
||||
let extra_wildcards = std::iter::repeat(&Anything).take(num_extra_wildcards);
|
||||
|
||||
let new_pats = (before.iter().chain(extra_wildcards).chain(after)).cloned();
|
||||
|
||||
spec_patterns.extend(new_pats);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug_assert_eq!(this_arity.min_len(), spec_arity.min_len());
|
||||
|
||||
spec_patterns.extend(args);
|
||||
}
|
||||
|
||||
Some(spec_patterns)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Some(Anything) => {
|
||||
// TODO order!
|
||||
let new_patterns = std::iter::repeat(Anything)
|
||||
.take(arity)
|
||||
.chain(patterns)
|
||||
.collect();
|
||||
Some(new_patterns)
|
||||
// The specialized fields for a `Anything` pattern with a list constructor is just
|
||||
// `Anything` repeated for the number of times we want to see the list pattern.
|
||||
spec_patterns.extend(std::iter::repeat(Anything).take(spec_arity.min_len()));
|
||||
Some(spec_patterns)
|
||||
}
|
||||
Some(Literal(_)) => unreachable!(
|
||||
r#"Compiler bug! After type checking, a constructor can never align with a literal: that should be a type error!"#
|
||||
Some(Ctor(..)) => internal_error!("After type checking, lists and constructors should never align in exhaustiveness checking"),
|
||||
Some(Literal(..)) => internal_error!("After type checking, lists and literals should never align in exhaustiveness checking"),
|
||||
None => internal_error!("Empty matrices should not get specialized"),
|
||||
}
|
||||
}
|
||||
|
||||
/// INVARIANT: (length row == N) ==> (length result == arity + N - 1)
|
||||
fn specialize_matrix_by_ctor(
|
||||
tag_id: TagId,
|
||||
arity: usize,
|
||||
old_matrix: &mut PatternMatrix,
|
||||
matrix: &mut PatternMatrix,
|
||||
) {
|
||||
for row in old_matrix.drain(..) {
|
||||
if let Some(spec_row) = specialize_row_by_ctor(tag_id, arity, row) {
|
||||
matrix.push(spec_row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// INVARIANT: (length row == N) ==> (length result == arity + N - 1)
|
||||
fn specialize_row_by_ctor(tag_id: TagId, arity: usize, mut row: Row) -> Option<Row> {
|
||||
let head = row.pop();
|
||||
let mut spec_patterns = row;
|
||||
|
||||
match head {
|
||||
Some(Ctor(_, id, args)) => {
|
||||
if id == tag_id {
|
||||
spec_patterns.extend(args);
|
||||
Some(spec_patterns)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Some(Anything) => {
|
||||
spec_patterns.extend(std::iter::repeat(Anything).take(arity));
|
||||
Some(spec_patterns)
|
||||
}
|
||||
Some(List(..)) => {
|
||||
internal_error!(r#"After type checking, a constructor can never align with a list"#)
|
||||
}
|
||||
Some(Literal(_)) => internal_error!(
|
||||
r#"After type checking, a constructor can never align with a literal: that should be a type error!"#
|
||||
),
|
||||
None => panic!("Compiler error! Empty matrices should not get specialized."),
|
||||
None => internal_error!("Empty matrices should not get specialized."),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -430,16 +601,21 @@ pub enum Complete {
|
|||
|
||||
fn is_complete(matrix: &RefPatternMatrix) -> Complete {
|
||||
let ctors = collect_ctors(matrix);
|
||||
let length = ctors.len();
|
||||
let mut it = ctors.into_iter();
|
||||
match ctors {
|
||||
CollectedCtors::NonExhaustiveAny | CollectedCtors::NonExhaustiveList(_) => Complete::No,
|
||||
CollectedCtors::Ctors(ctors) => {
|
||||
let length = ctors.len();
|
||||
let mut it = ctors.into_iter();
|
||||
|
||||
match it.next() {
|
||||
None => Complete::No,
|
||||
Some((_, Union { alternatives, .. })) => {
|
||||
if length == alternatives.len() {
|
||||
Complete::Yes(alternatives)
|
||||
} else {
|
||||
Complete::No
|
||||
match it.next() {
|
||||
None => Complete::No,
|
||||
Some((_, Union { alternatives, .. })) => {
|
||||
if length == alternatives.len() {
|
||||
Complete::Yes(alternatives)
|
||||
} else {
|
||||
Complete::No
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -452,14 +628,219 @@ type PatternMatrix = Vec<Vec<Pattern>>;
|
|||
type RefRow = [Pattern];
|
||||
type Row = Vec<Pattern>;
|
||||
|
||||
fn collect_ctors(matrix: &RefPatternMatrix) -> MutMap<TagId, Union> {
|
||||
let mut ctors = MutMap::default();
|
||||
enum CollectedCtors {
|
||||
NonExhaustiveAny,
|
||||
NonExhaustiveList(Vec<ListArity>),
|
||||
Ctors(MutMap<TagId, Union>),
|
||||
}
|
||||
|
||||
for row in matrix {
|
||||
if let Some(Ctor(union, id, _)) = row.last() {
|
||||
ctors.insert(*id, union.clone());
|
||||
}
|
||||
fn collect_ctors(matrix: &RefPatternMatrix) -> CollectedCtors {
|
||||
if matrix.is_empty() {
|
||||
return CollectedCtors::NonExhaustiveAny;
|
||||
}
|
||||
|
||||
ctors
|
||||
let first_row = &matrix[0];
|
||||
|
||||
if let Some(ctor) = first_row.last() {
|
||||
match ctor {
|
||||
Anything => CollectedCtors::NonExhaustiveAny,
|
||||
Pattern::Literal(_) => CollectedCtors::NonExhaustiveAny,
|
||||
List(_, _) => {
|
||||
let list_ctors = build_list_ctors_covering_patterns(
|
||||
ListArity::ANY,
|
||||
filter_matrix_list_ctors(matrix),
|
||||
);
|
||||
|
||||
CollectedCtors::NonExhaustiveList(list_ctors)
|
||||
}
|
||||
Pattern::Ctor(_, _, _) => {
|
||||
let mut ctors = MutMap::default();
|
||||
|
||||
for row in matrix {
|
||||
if let Some(Ctor(union, id, _)) = row.last() {
|
||||
ctors.insert(*id, union.clone());
|
||||
}
|
||||
}
|
||||
|
||||
CollectedCtors::Ctors(ctors)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CollectedCtors::NonExhaustiveAny
|
||||
}
|
||||
}
|
||||
|
||||
/// Largely derived from Rust's list-pattern exhaustiveness checking algorithm: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_build/thir/pattern/usefulness/index.html
|
||||
/// Dual-licensed under MIT and Apache licenses.
|
||||
/// Thank you, Rust contributors.
|
||||
///
|
||||
/// Calculates the list constructors that are covered by a given [slice constructor][ListArity::Slice],
|
||||
/// relative to other list constructors matched by a series of patterns.
|
||||
///
|
||||
/// This is relevant for both exhaustiveness and redundancy checking; to understand the motivation,
|
||||
/// let's start with the exhaustiveness checking case.
|
||||
///
|
||||
/// # Exhaustiveness Checking
|
||||
///
|
||||
/// All list constructors are exausted by the pattern [..], which actually represents the infinite
|
||||
/// series of constructors
|
||||
/// []
|
||||
/// [_]
|
||||
/// [_, _]
|
||||
/// ...
|
||||
///
|
||||
/// But we don't need to enumerate that infinite series to check if a series of list patterns is exhaustive -
|
||||
/// we only need to enumerate a finite number of constructors, up to the largest exact-size list
|
||||
/// pattern not covered by the patterns, or the largest slice pattern covered by the patterns.
|
||||
///
|
||||
/// ## Exact-sized patterns
|
||||
///
|
||||
/// Say we have patterns
|
||||
/// [_] -> ..
|
||||
/// [_, _] -> ..
|
||||
/// To exhaustiveness-check these patterns, we only need to build the subset of `[..]` constructors
|
||||
/// []
|
||||
/// [_]
|
||||
/// [_, _]
|
||||
/// [_, _, _, ..]
|
||||
/// to cover all list constructors that may or may not be matched by the patterns (in this case
|
||||
/// not, because `[]` is not matched, and the last constructor `[_, _, _, ..]` is not matched).
|
||||
///
|
||||
/// We include `[_, _, _, ..]` here because during exhaustiveness checking, we specialize list
|
||||
/// patterns **by exact size**, not by ranges. That means that is we stopped enumerating the
|
||||
/// constructors needed at `[_, _, ..]`, when specializing the list patterns against `[_, _, ..]`,
|
||||
/// we would see that the last pattern `[_, _] -> ..` exhausts it.
|
||||
///
|
||||
/// So, in the presence of exact-size constructors, we want to include a slice constructor that is
|
||||
/// larger than all other exact-size list pattern.
|
||||
///
|
||||
/// ## Slice patterns
|
||||
///
|
||||
/// Say we have patterns
|
||||
/// [1] -> ..
|
||||
/// [2, ..] -> ..
|
||||
/// now it's enough to just build
|
||||
/// []
|
||||
/// [_, ..]
|
||||
/// as possible constructors, since the last constructor `[_, ..]` will specialize both patterns to
|
||||
/// [1] -> ..
|
||||
/// [2] -> ..
|
||||
/// and if these patterns are exhaustive w.r.t. their arguments (`1` and `2`, which they are not,
|
||||
/// since number literals are not exhaustive), then the whole pattern must be exhaustive, since the
|
||||
/// largest slice constructor `[_, ..]` will cover the remaining infinite number of list constructors.
|
||||
///
|
||||
/// You can see that this holds with slice constructors that match elements at their head and tail
|
||||
/// as well:
|
||||
/// [{}, ..] -> ..
|
||||
/// [.., {}] -> ..
|
||||
/// Here again it's enough to just build the constructors [] and [_, ..] to match against -
|
||||
/// notice that above slices of arity `1`, the patterns above do not provide any more information,
|
||||
/// since they match any additional elements at the tail and head, respectively.
|
||||
///
|
||||
/// So, if they are exhaustive at arity `1`, they must be exhaustive at any higher arity.
|
||||
///
|
||||
/// In fact, in this case, if we are matching against `List {}`, the second pattern redundant!
|
||||
///
|
||||
/// # Redundancy checking
|
||||
///
|
||||
/// Redundancy checking (in general, and for list patterns) is the same as exhaustiveness checking,
|
||||
/// except that instead of checking whether `[..]` is covered by all patterns, we want to check if
|
||||
/// the list constructor of a pattern introduces any more information than previous patterns we've
|
||||
/// seen.
|
||||
///
|
||||
/// Let's say we're redundancy checking the pattern marked by `*`
|
||||
/// [] -> ..
|
||||
/// [_] -> ..
|
||||
/// (*) [.., _] -> ..
|
||||
///
|
||||
/// The list constructors this pattern introduces are the infinite series [_], [_, _], ...
|
||||
/// But the only ones relevant, relevant to the patterns we've already seen, are
|
||||
/// [_]
|
||||
/// [_, _]
|
||||
/// (Notice that the enumeration algorithm is the same as for `[..]` in the presence of exact-size
|
||||
/// slices, just that the starting size differs - due to the tail matched by this pattern)
|
||||
///
|
||||
/// During checking we'll see that the `[_, _]` pattern is not already covered, so `[.., _]` is in
|
||||
/// fact not redundant.
|
||||
///
|
||||
/// On the other hand, suppose we have
|
||||
/// [] -> ..
|
||||
/// [_, ..] -> ..
|
||||
/// (*) [.., _] -> ..
|
||||
///
|
||||
/// Again enumerating the relevant constructors of `[.., _]` relative to the other patterns, we find
|
||||
/// them to be
|
||||
/// []
|
||||
/// [.., _]
|
||||
/// the first is already matched by the first pattern `[] -> ..`, and the latter specialized to
|
||||
/// `[_]`, which in fact is covered by the second pattern `[_, ..] -> ..`. So the pattern marked by (*)
|
||||
/// is indeed redundant.
|
||||
///
|
||||
/// # All together
|
||||
///
|
||||
/// So the idea to cover the infinite # of list constructors enumerated by a [slice][ListArity::Slice],
|
||||
/// while specializing to the constructors that the user has provided, is as follows:
|
||||
/// - Build [exact][ListArity::Exact] constructor variants for everything up to the max slice
|
||||
/// constructor size, L.
|
||||
/// - Then, the infinite # of list constructors is covered by the [0..L) exact-size constructors, and
|
||||
/// the last slice constructor, that covers size [L..∞).
|
||||
///
|
||||
/// If we might only see [exact][ListArity::Exact] constructors along the way, we want to pick the
|
||||
/// max slice size L that is larger than all of those exact size constructors.
|
||||
///
|
||||
/// But for slice constructors, we can just pick the largest slice, since that will cover slices of
|
||||
/// that size, and any larger size.
|
||||
///
|
||||
/// Putting that together, we calculate L via
|
||||
///
|
||||
/// L = max(max_exact_len + 1, max_prefix_len + max_suffix_len)
|
||||
fn build_list_ctors_covering_patterns(
|
||||
list_arity: ListArity,
|
||||
list_pattern_arities: impl IntoIterator<Item = ListArity>,
|
||||
) -> std::vec::Vec<ListArity> {
|
||||
match list_arity {
|
||||
ListArity::Exact(_) => {
|
||||
// Exact-size lists can only cover themselves..
|
||||
vec![list_arity]
|
||||
}
|
||||
ListArity::Slice(prefix_len, suffix_len) => {
|
||||
let min_len = prefix_len + suffix_len;
|
||||
|
||||
let mut max_exact_len = 0;
|
||||
let mut max_prefix_len = prefix_len;
|
||||
let mut max_suffix_len = suffix_len;
|
||||
|
||||
for arity in list_pattern_arities {
|
||||
match arity {
|
||||
ListArity::Exact(n) => max_exact_len = max_exact_len.max(n),
|
||||
ListArity::Slice(prefix, suffix) => {
|
||||
max_prefix_len = max_prefix_len.max(prefix);
|
||||
max_suffix_len = max_suffix_len.max(suffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let (inf_cover_prefix, inf_cover_suffix) = {
|
||||
if max_exact_len + 1 >= max_prefix_len + max_suffix_len {
|
||||
max_prefix_len = max_exact_len + 1 - max_suffix_len;
|
||||
}
|
||||
(max_prefix_len, max_suffix_len)
|
||||
};
|
||||
let l = inf_cover_prefix + inf_cover_suffix;
|
||||
|
||||
let exact_size_lists = (min_len..l) // exclusive
|
||||
.map(ListArity::Exact);
|
||||
|
||||
exact_size_lists
|
||||
.chain([ListArity::Slice(inf_cover_prefix, inf_cover_suffix)])
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_matrix_list_ctors(matrix: &RefPatternMatrix) -> impl Iterator<Item = ListArity> + '_ {
|
||||
matrix.iter().filter_map(|ctor| match ctor.last() {
|
||||
Some(List(ar, _)) => Some(*ar),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -166,8 +166,8 @@ impl<'a> Formattable for TypeAnnotation<'a> {
|
|||
|
||||
Wildcard | Inferred | BoundVariable(_) | Malformed(_) => false,
|
||||
Function(args, result) => {
|
||||
(&result.value).is_multiline()
|
||||
|| args.iter().any(|loc_arg| (&loc_arg.value).is_multiline())
|
||||
result.value.is_multiline()
|
||||
|| args.iter().any(|loc_arg| loc_arg.value.is_multiline())
|
||||
}
|
||||
Apply(_, _, args) => args.iter().any(|loc_arg| loc_arg.value.is_multiline()),
|
||||
As(lhs, _, _) => lhs.value.is_multiline(),
|
||||
|
@ -226,7 +226,7 @@ impl<'a> Formattable for TypeAnnotation<'a> {
|
|||
buf.newline();
|
||||
}
|
||||
|
||||
(&argument.value).format_with_options(
|
||||
argument.value.format_with_options(
|
||||
buf,
|
||||
Parens::InFunctionType,
|
||||
Newlines::No,
|
||||
|
@ -251,7 +251,8 @@ impl<'a> Formattable for TypeAnnotation<'a> {
|
|||
buf.push_str("->");
|
||||
buf.spaces(1);
|
||||
|
||||
(&ret.value).format_with_options(buf, Parens::InFunctionType, Newlines::No, indent);
|
||||
ret.value
|
||||
.format_with_options(buf, Parens::InFunctionType, Newlines::No, indent);
|
||||
|
||||
if needs_parens {
|
||||
buf.push(')')
|
||||
|
@ -275,12 +276,9 @@ impl<'a> Formattable for TypeAnnotation<'a> {
|
|||
|
||||
for argument in *arguments {
|
||||
buf.spaces(1);
|
||||
(&argument.value).format_with_options(
|
||||
buf,
|
||||
Parens::InApply,
|
||||
Newlines::No,
|
||||
indent,
|
||||
);
|
||||
argument
|
||||
.value
|
||||
.format_with_options(buf, Parens::InApply, Newlines::No, indent);
|
||||
}
|
||||
|
||||
if write_parens {
|
||||
|
@ -371,12 +369,12 @@ impl<'a> Formattable for AssignedField<'a, TypeAnnotation<'a>> {
|
|||
fn format_with_options<'buf>(
|
||||
&self,
|
||||
buf: &mut Buf<'buf>,
|
||||
parens: Parens,
|
||||
_parens: Parens,
|
||||
newlines: Newlines,
|
||||
indent: u16,
|
||||
) {
|
||||
// we abuse the `Newlines` type to decide between multiline or single-line layout
|
||||
format_assigned_field_help(self, buf, parens, indent, 1, newlines == Newlines::Yes);
|
||||
format_assigned_field_help(self, buf, indent, 1, newlines == Newlines::Yes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,12 +386,12 @@ impl<'a> Formattable for AssignedField<'a, Expr<'a>> {
|
|||
fn format_with_options<'buf>(
|
||||
&self,
|
||||
buf: &mut Buf<'buf>,
|
||||
parens: Parens,
|
||||
_parens: Parens,
|
||||
newlines: Newlines,
|
||||
indent: u16,
|
||||
) {
|
||||
// we abuse the `Newlines` type to decide between multiline or single-line layout
|
||||
format_assigned_field_help(self, buf, parens, indent, 0, newlines == Newlines::Yes);
|
||||
format_assigned_field_help(self, buf, indent, 0, newlines == Newlines::Yes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -413,7 +411,6 @@ fn is_multiline_assigned_field_help<T: Formattable>(afield: &AssignedField<'_, T
|
|||
fn format_assigned_field_help<'a, 'buf, T>(
|
||||
zelf: &AssignedField<'a, T>,
|
||||
buf: &mut Buf<'buf>,
|
||||
parens: Parens,
|
||||
indent: u16,
|
||||
separator_spaces: usize,
|
||||
is_multiline: bool,
|
||||
|
@ -466,24 +463,10 @@ fn format_assigned_field_help<'a, 'buf, T>(
|
|||
}
|
||||
AssignedField::SpaceBefore(sub_field, spaces) => {
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
format_assigned_field_help(
|
||||
sub_field,
|
||||
buf,
|
||||
parens,
|
||||
indent,
|
||||
separator_spaces,
|
||||
is_multiline,
|
||||
);
|
||||
format_assigned_field_help(sub_field, buf, indent, separator_spaces, is_multiline);
|
||||
}
|
||||
AssignedField::SpaceAfter(sub_field, spaces) => {
|
||||
format_assigned_field_help(
|
||||
sub_field,
|
||||
buf,
|
||||
parens,
|
||||
indent,
|
||||
separator_spaces,
|
||||
is_multiline,
|
||||
);
|
||||
format_assigned_field_help(sub_field, buf, indent, separator_spaces, is_multiline);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
}
|
||||
Malformed(raw) => {
|
||||
|
@ -497,7 +480,7 @@ impl<'a> Formattable for Tag<'a> {
|
|||
use self::Tag::*;
|
||||
|
||||
match self {
|
||||
Apply { args, .. } => args.iter().any(|arg| (&arg.value).is_multiline()),
|
||||
Apply { args, .. } => args.iter().any(|arg| arg.value.is_multiline()),
|
||||
Tag::SpaceBefore(_, _) | Tag::SpaceAfter(_, _) => true,
|
||||
Malformed(text) => text.chars().any(|c| c == '\n'),
|
||||
}
|
||||
|
|
|
@ -542,7 +542,7 @@ fn fmt_binops<'a, 'buf>(
|
|||
indent: u16,
|
||||
) {
|
||||
let is_multiline = part_of_multi_line_binops
|
||||
|| (&loc_right_side.value).is_multiline()
|
||||
|| loc_right_side.value.is_multiline()
|
||||
|| lefts.iter().any(|(expr, _)| expr.value.is_multiline());
|
||||
|
||||
for (loc_left_side, loc_binop) in lefts {
|
||||
|
@ -1045,7 +1045,7 @@ fn fmt_closure<'a, 'buf>(
|
|||
|
||||
buf.push_str("->");
|
||||
|
||||
let is_multiline = (&loc_ret.value).is_multiline();
|
||||
let is_multiline = loc_ret.value.is_multiline();
|
||||
|
||||
// If the body is multiline, go down a line and indent.
|
||||
let body_indent = if is_multiline {
|
||||
|
@ -1156,7 +1156,7 @@ fn fmt_backpassing<'a, 'buf>(
|
|||
|
||||
buf.push_str("<-");
|
||||
|
||||
let is_multiline = (&loc_ret.value).is_multiline();
|
||||
let is_multiline = loc_ret.value.is_multiline();
|
||||
|
||||
// If the body is multiline, go down a line and indent.
|
||||
let body_indent = if is_multiline {
|
||||
|
|
|
@ -152,6 +152,7 @@ impl<'a> Formattable for Pattern<'a> {
|
|||
}
|
||||
StrLiteral(literal) => fmt_str_literal(buf, *literal, indent),
|
||||
SingleQuote(string) => {
|
||||
buf.indent(indent);
|
||||
buf.push('\'');
|
||||
buf.push_str(string);
|
||||
buf.push('\'');
|
||||
|
|
|
@ -3864,6 +3864,17 @@ mod test_fmt {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_with_single_quote_char() {
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
when x is
|
||||
'0' -> 0
|
||||
'1' -> 1
|
||||
"#
|
||||
));
|
||||
}
|
||||
|
||||
// NEWLINES
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -19,7 +19,7 @@ macro_rules! disassembler_test {
|
|||
// TODO: Not sure if there is a better way to merge these together,
|
||||
// but I like the end use of this a lot better than the old tests.
|
||||
($assemble_fn: expr, $format_fn: expr) => {{
|
||||
use crate::generic64::disassembler_test_macro::merge_instructions_without_line_numbers;
|
||||
use $crate::generic64::disassembler_test_macro::merge_instructions_without_line_numbers;
|
||||
let arena = bumpalo::Bump::new();
|
||||
let (mut buf, cs) = setup_capstone_and_arena(&arena);
|
||||
$assemble_fn(&mut buf);
|
||||
|
|
|
@ -1011,7 +1011,7 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
|||
|
||||
#[inline(always)]
|
||||
fn call(buf: &mut Vec<'_, u8>, relocs: &mut Vec<'_, Relocation>, fn_name: String) {
|
||||
buf.extend(&[0xE8, 0x00, 0x00, 0x00, 0x00]);
|
||||
buf.extend([0xE8, 0x00, 0x00, 0x00, 0x00]);
|
||||
relocs.push(Relocation::LinkedFunction {
|
||||
offset: buf.len() as u64 - 4,
|
||||
name: fn_name,
|
||||
|
@ -1478,7 +1478,7 @@ fn binop_reg64_reg64(
|
|||
let rex = add_reg_extension(src, rex);
|
||||
let dst_mod = dst as u8 % 8;
|
||||
let src_mod = (src as u8 % 8) << 3;
|
||||
buf.extend(&[rex, op_code, 0xC0 | dst_mod | src_mod]);
|
||||
buf.extend([rex, op_code, 0xC0 | dst_mod | src_mod]);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -1493,7 +1493,7 @@ fn extended_binop_reg64_reg64(
|
|||
let rex = add_reg_extension(src, rex);
|
||||
let dst_mod = dst as u8 % 8;
|
||||
let src_mod = (src as u8 % 8) << 3;
|
||||
buf.extend(&[rex, op_code1, op_code2, 0xC0 | dst_mod | src_mod]);
|
||||
buf.extend([rex, op_code1, op_code2, 0xC0 | dst_mod | src_mod]);
|
||||
}
|
||||
|
||||
// Below here are the functions for all of the assembly instructions.
|
||||
|
@ -1508,8 +1508,8 @@ fn add_reg64_imm32(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, imm: i32) {
|
|||
let rex = add_rm_extension(dst, REX_W);
|
||||
let dst_mod = dst as u8 % 8;
|
||||
buf.reserve(7);
|
||||
buf.extend(&[rex, 0x81, 0xC0 | dst_mod]);
|
||||
buf.extend(&imm.to_le_bytes());
|
||||
buf.extend([rex, 0x81, 0xC0 | dst_mod]);
|
||||
buf.extend(imm.to_le_bytes());
|
||||
}
|
||||
|
||||
/// `ADD r/m64,r64` -> Add r64 to r/m64.
|
||||
|
@ -1547,7 +1547,7 @@ fn addsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64Fl
|
|||
let src_high = src as u8 > 7;
|
||||
let src_mod = src as u8 % 8;
|
||||
if dst_high || src_high {
|
||||
buf.extend(&[
|
||||
buf.extend([
|
||||
0xF2,
|
||||
0x40 | ((dst_high as u8) << 2) | (src_high as u8),
|
||||
0x0F,
|
||||
|
@ -1555,7 +1555,7 @@ fn addsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64Fl
|
|||
0xC0 | (dst_mod << 3) | (src_mod),
|
||||
])
|
||||
} else {
|
||||
buf.extend(&[0xF2, 0x0F, 0x58, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
buf.extend([0xF2, 0x0F, 0x58, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1567,7 +1567,7 @@ fn addss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64Fl
|
|||
let src_high = src as u8 > 7;
|
||||
let src_mod = src as u8 % 8;
|
||||
if dst_high || src_high {
|
||||
buf.extend(&[
|
||||
buf.extend([
|
||||
0xF3,
|
||||
0x40 | ((dst_high as u8) << 2) | (src_high as u8),
|
||||
0x0F,
|
||||
|
@ -1575,7 +1575,7 @@ fn addss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64Fl
|
|||
0xC0 | (dst_mod << 3) | (src_mod),
|
||||
])
|
||||
} else {
|
||||
buf.extend(&[0xF3, 0x0F, 0x58, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
buf.extend([0xF3, 0x0F, 0x58, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1587,7 +1587,7 @@ fn mulsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64Fl
|
|||
let src_high = src as u8 > 7;
|
||||
let src_mod = src as u8 % 8;
|
||||
if dst_high || src_high {
|
||||
buf.extend(&[
|
||||
buf.extend([
|
||||
0xF2,
|
||||
0x40 | ((dst_high as u8) << 2) | (src_high as u8),
|
||||
0x0F,
|
||||
|
@ -1595,7 +1595,7 @@ fn mulsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64Fl
|
|||
0xC0 | (dst_mod << 3) | (src_mod),
|
||||
])
|
||||
} else {
|
||||
buf.extend(&[0xF2, 0x0F, 0x59, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
buf.extend([0xF2, 0x0F, 0x59, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1607,7 +1607,7 @@ fn divss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64Fl
|
|||
let src_high = src as u8 > 7;
|
||||
let src_mod = src as u8 % 8;
|
||||
if dst_high || src_high {
|
||||
buf.extend(&[
|
||||
buf.extend([
|
||||
0xF3,
|
||||
0x40 | ((dst_high as u8) << 2) | (src_high as u8),
|
||||
0x0F,
|
||||
|
@ -1615,7 +1615,7 @@ fn divss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64Fl
|
|||
0xC0 | (dst_mod << 3) | (src_mod),
|
||||
])
|
||||
} else {
|
||||
buf.extend(&[0xF3, 0x0F, 0x5E, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
buf.extend([0xF3, 0x0F, 0x5E, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1627,7 +1627,7 @@ fn divsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64Fl
|
|||
let src_high = src as u8 > 7;
|
||||
let src_mod = src as u8 % 8;
|
||||
if dst_high || src_high {
|
||||
buf.extend(&[
|
||||
buf.extend([
|
||||
0xF2,
|
||||
0x40 | ((dst_high as u8) << 2) | (src_high as u8),
|
||||
0x0F,
|
||||
|
@ -1635,7 +1635,7 @@ fn divsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64Fl
|
|||
0xC0 | (dst_mod << 3) | (src_mod),
|
||||
])
|
||||
} else {
|
||||
buf.extend(&[0xF2, 0x0F, 0x5E, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
buf.extend([0xF2, 0x0F, 0x5E, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1647,7 +1647,7 @@ fn mulss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64Fl
|
|||
let src_high = src as u8 > 7;
|
||||
let src_mod = src as u8 % 8;
|
||||
if dst_high || src_high {
|
||||
buf.extend(&[
|
||||
buf.extend([
|
||||
0xF3,
|
||||
0x40 | ((dst_high as u8) << 2) | (src_high as u8),
|
||||
0x0F,
|
||||
|
@ -1655,7 +1655,7 @@ fn mulss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64Fl
|
|||
0xC0 | (dst_mod << 3) | (src_mod),
|
||||
])
|
||||
} else {
|
||||
buf.extend(&[0xF3, 0x0F, 0x59, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
buf.extend([0xF3, 0x0F, 0x59, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1667,7 +1667,7 @@ fn andpd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64Fl
|
|||
let src_mod = src as u8 % 8;
|
||||
|
||||
if dst_high || src_high {
|
||||
buf.extend(&[
|
||||
buf.extend([
|
||||
0x66,
|
||||
0x40 | ((dst_high as u8) << 2) | (src_high as u8),
|
||||
0x0F,
|
||||
|
@ -1675,7 +1675,7 @@ fn andpd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64Fl
|
|||
0xC0 | (dst_mod << 3) | (src_mod),
|
||||
])
|
||||
} else {
|
||||
buf.extend(&[0x66, 0x0F, 0x54, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
buf.extend([0x66, 0x0F, 0x54, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1684,7 +1684,7 @@ fn andpd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64Fl
|
|||
fn and_reg64_imm8(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, imm: i8) {
|
||||
let rex = add_rm_extension(dst, REX_W);
|
||||
let dst_mod = dst as u8 % 8;
|
||||
buf.extend(&[rex, 0x83, 0xE0 | dst_mod, imm as u8]);
|
||||
buf.extend([rex, 0x83, 0xE0 | dst_mod, imm as u8]);
|
||||
}
|
||||
|
||||
/// `CMOVL r64,r/m64` -> Move if less (SF≠ OF).
|
||||
|
@ -1694,7 +1694,7 @@ fn cmovl_reg64_reg64(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, src: X86_64Ge
|
|||
let rex = add_rm_extension(src, rex);
|
||||
let dst_mod = (dst as u8 % 8) << 3;
|
||||
let src_mod = src as u8 % 8;
|
||||
buf.extend(&[rex, 0x0F, 0x4C, 0xC0 | dst_mod | src_mod]);
|
||||
buf.extend([rex, 0x0F, 0x4C, 0xC0 | dst_mod | src_mod]);
|
||||
}
|
||||
|
||||
/// `CMP r/m64,i32` -> Compare i32 to r/m64.
|
||||
|
@ -1703,8 +1703,8 @@ fn cmp_reg64_imm32(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, imm: i32) {
|
|||
let rex = add_rm_extension(dst, REX_W);
|
||||
let dst_mod = dst as u8 % 8;
|
||||
buf.reserve(7);
|
||||
buf.extend(&[rex, 0x81, 0xF8 | dst_mod]);
|
||||
buf.extend(&imm.to_le_bytes());
|
||||
buf.extend([rex, 0x81, 0xF8 | dst_mod]);
|
||||
buf.extend(imm.to_le_bytes());
|
||||
}
|
||||
|
||||
/// `CMP r/m64,r64` -> Compare r64 to r/m64.
|
||||
|
@ -1738,7 +1738,7 @@ fn mul_reg64_reg64(buf: &mut Vec<'_, u8>, src: X86_64GeneralReg) {
|
|||
rex |= REX_PREFIX_B;
|
||||
}
|
||||
|
||||
buf.extend(&[rex, 0xF7, 0b1110_0000 | (src as u8 % 8)]);
|
||||
buf.extend([rex, 0xF7, 0b1110_0000 | (src as u8 % 8)]);
|
||||
}
|
||||
|
||||
/// `IDIV r/m64` -> Signed divide RDX:RAX by r/m64, with result stored in RAX ← Quotient, RDX ← Remainder.
|
||||
|
@ -1756,9 +1756,9 @@ fn idiv_reg64_reg64(buf: &mut Vec<'_, u8>, src: X86_64GeneralReg) {
|
|||
//
|
||||
// The CQO instruction (available in 64-bit mode only) copies the sign (bit 63)
|
||||
// of the value in the RAX register into every bit position in the RDX register
|
||||
buf.extend(&[0x48, 0x99]);
|
||||
buf.extend([0x48, 0x99]);
|
||||
|
||||
buf.extend(&[rex, 0xF7, 0b1111_1000 | (src as u8 % 8)]);
|
||||
buf.extend([rex, 0xF7, 0b1111_1000 | (src as u8 % 8)]);
|
||||
}
|
||||
|
||||
/// `DIV r/m64` -> Unsigned divide RDX:RAX by r/m64, with result stored in RAX ← Quotient, RDX ← Remainder.
|
||||
|
@ -1776,10 +1776,10 @@ fn udiv_reg64_reg64(buf: &mut Vec<'_, u8>, src: X86_64GeneralReg) {
|
|||
//
|
||||
// The CQO instruction (available in 64-bit mode only) copies the sign (bit 63)
|
||||
// of the value in the RAX register into every bit position in the RDX register
|
||||
buf.extend(&[0x48, 0x99]);
|
||||
buf.extend([0x48, 0x99]);
|
||||
|
||||
// adds a cqo (convert doubleword to quadword)
|
||||
buf.extend(&[rex, 0xF7, 0b1111_0000 | (src as u8 % 8)]);
|
||||
buf.extend([rex, 0xF7, 0b1111_0000 | (src as u8 % 8)]);
|
||||
}
|
||||
|
||||
/// Jump near, relative, RIP = RIP + 32-bit displacement sign extended to 64-bits.
|
||||
|
@ -1787,7 +1787,7 @@ fn udiv_reg64_reg64(buf: &mut Vec<'_, u8>, src: X86_64GeneralReg) {
|
|||
fn jmp_imm32(buf: &mut Vec<'_, u8>, imm: i32) {
|
||||
buf.reserve(5);
|
||||
buf.push(0xE9);
|
||||
buf.extend(&imm.to_le_bytes());
|
||||
buf.extend(imm.to_le_bytes());
|
||||
}
|
||||
|
||||
/// Jump near if not equal (ZF=0).
|
||||
|
@ -1796,7 +1796,7 @@ fn jne_imm32(buf: &mut Vec<'_, u8>, imm: i32) {
|
|||
buf.reserve(6);
|
||||
buf.push(0x0F);
|
||||
buf.push(0x85);
|
||||
buf.extend(&imm.to_le_bytes());
|
||||
buf.extend(imm.to_le_bytes());
|
||||
}
|
||||
|
||||
/// `MOV r/m64, imm32` -> Move imm32 sign extended to 64-bits to r/m64.
|
||||
|
@ -1805,8 +1805,8 @@ fn mov_reg64_imm32(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, imm: i32) {
|
|||
let rex = add_rm_extension(dst, REX_W);
|
||||
let dst_mod = dst as u8 % 8;
|
||||
buf.reserve(7);
|
||||
buf.extend(&[rex, 0xC7, 0xC0 | dst_mod]);
|
||||
buf.extend(&imm.to_le_bytes());
|
||||
buf.extend([rex, 0xC7, 0xC0 | dst_mod]);
|
||||
buf.extend(imm.to_le_bytes());
|
||||
}
|
||||
|
||||
/// `MOV r64, imm64` -> Move imm64 to r64.
|
||||
|
@ -1818,8 +1818,8 @@ fn mov_reg64_imm64(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, imm: i64) {
|
|||
let rex = add_opcode_extension(dst, REX_W);
|
||||
let dst_mod = dst as u8 % 8;
|
||||
buf.reserve(10);
|
||||
buf.extend(&[rex, 0xB8 | dst_mod]);
|
||||
buf.extend(&imm.to_le_bytes());
|
||||
buf.extend([rex, 0xB8 | dst_mod]);
|
||||
buf.extend(imm.to_le_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1854,12 +1854,12 @@ fn mov_base64_offset32_reg64(
|
|||
let src_mod = (src as u8 % 8) << 3;
|
||||
let base_mod = base as u8 % 8;
|
||||
buf.reserve(8);
|
||||
buf.extend(&[rex, 0x89, 0x80 | src_mod | base_mod]);
|
||||
buf.extend([rex, 0x89, 0x80 | src_mod | base_mod]);
|
||||
// Using RSP or R12 requires a secondary index byte.
|
||||
if base == X86_64GeneralReg::RSP || base == X86_64GeneralReg::R12 {
|
||||
buf.push(0x24);
|
||||
}
|
||||
buf.extend(&offset.to_le_bytes());
|
||||
buf.extend(offset.to_le_bytes());
|
||||
}
|
||||
|
||||
/// `MOV r64,r/m64` -> Move r/m64 to r64, where m64 references a base + offset.
|
||||
|
@ -1875,12 +1875,12 @@ fn mov_reg64_base64_offset32(
|
|||
let dst_mod = (dst as u8 % 8) << 3;
|
||||
let base_mod = base as u8 % 8;
|
||||
buf.reserve(8);
|
||||
buf.extend(&[rex, 0x8B, 0x80 | dst_mod | base_mod]);
|
||||
buf.extend([rex, 0x8B, 0x80 | dst_mod | base_mod]);
|
||||
// Using RSP or R12 requires a secondary index byte.
|
||||
if base == X86_64GeneralReg::RSP || base == X86_64GeneralReg::R12 {
|
||||
buf.push(0x24);
|
||||
}
|
||||
buf.extend(&offset.to_le_bytes());
|
||||
buf.extend(offset.to_le_bytes());
|
||||
}
|
||||
|
||||
/// `MOVZX r64,r/m8` -> Move r/m8 with zero extention to r64, where m8 references a base + offset.
|
||||
|
@ -1896,12 +1896,12 @@ fn movzx_reg64_base8_offset32(
|
|||
let dst_mod = (dst as u8 % 8) << 3;
|
||||
let base_mod = base as u8 % 8;
|
||||
buf.reserve(9);
|
||||
buf.extend(&[rex, 0x0F, 0xB6, 0x80 | dst_mod | base_mod]);
|
||||
buf.extend([rex, 0x0F, 0xB6, 0x80 | dst_mod | base_mod]);
|
||||
// Using RSP or R12 requires a secondary index byte.
|
||||
if base == X86_64GeneralReg::RSP || base == X86_64GeneralReg::R12 {
|
||||
buf.push(0x24);
|
||||
}
|
||||
buf.extend(&offset.to_le_bytes());
|
||||
buf.extend(offset.to_le_bytes());
|
||||
}
|
||||
|
||||
/// `MOVSD xmm1,xmm2` -> Move scalar double-precision floating-point value from xmm2 to xmm1 register.
|
||||
|
@ -1922,7 +1922,7 @@ fn raw_movsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_
|
|||
let src_high = src as u8 > 7;
|
||||
let src_mod = src as u8 % 8;
|
||||
if dst_high || src_high {
|
||||
buf.extend(&[
|
||||
buf.extend([
|
||||
0xF2,
|
||||
0x40 | ((dst_high as u8) << 2) | (src_high as u8),
|
||||
0x0F,
|
||||
|
@ -1930,7 +1930,7 @@ fn raw_movsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_
|
|||
0xC0 | (dst_mod << 3) | (src_mod),
|
||||
])
|
||||
} else {
|
||||
buf.extend(&[0xF2, 0x0F, 0x10, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
buf.extend([0xF2, 0x0F, 0x10, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1952,7 +1952,7 @@ fn raw_movss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_
|
|||
let src_high = src as u8 > 7;
|
||||
let src_mod = src as u8 % 8;
|
||||
if dst_high || src_high {
|
||||
buf.extend(&[
|
||||
buf.extend([
|
||||
0xF3,
|
||||
0x40 | ((dst_high as u8) << 2) | (src_high as u8),
|
||||
0x0F,
|
||||
|
@ -1960,7 +1960,7 @@ fn raw_movss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_
|
|||
0xC0 | (dst_mod << 3) | (src_mod),
|
||||
])
|
||||
} else {
|
||||
buf.extend(&[0xF3, 0x0F, 0x10, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
buf.extend([0xF3, 0x0F, 0x10, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1970,12 +1970,12 @@ fn movss_freg32_rip_offset32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, offset:
|
|||
let dst_mod = dst as u8 % 8;
|
||||
if dst as u8 > 7 {
|
||||
buf.reserve(9);
|
||||
buf.extend(&[0xF3, 0x44, 0x0F, 0x10, 0x05 | (dst_mod << 3)]);
|
||||
buf.extend([0xF3, 0x44, 0x0F, 0x10, 0x05 | (dst_mod << 3)]);
|
||||
} else {
|
||||
buf.reserve(8);
|
||||
buf.extend(&[0xF3, 0x0F, 0x10, 0x05 | (dst_mod << 3)]);
|
||||
buf.extend([0xF3, 0x0F, 0x10, 0x05 | (dst_mod << 3)]);
|
||||
}
|
||||
buf.extend(&offset.to_le_bytes());
|
||||
buf.extend(offset.to_le_bytes());
|
||||
}
|
||||
|
||||
// `MOVSD xmm, m64` -> Load scalar double-precision floating-point value from m64 to xmm register.
|
||||
|
@ -1984,12 +1984,12 @@ fn movsd_freg64_rip_offset32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, offset:
|
|||
let dst_mod = dst as u8 % 8;
|
||||
if dst as u8 > 7 {
|
||||
buf.reserve(9);
|
||||
buf.extend(&[0xF2, 0x44, 0x0F, 0x10, 0x05 | (dst_mod << 3)]);
|
||||
buf.extend([0xF2, 0x44, 0x0F, 0x10, 0x05 | (dst_mod << 3)]);
|
||||
} else {
|
||||
buf.reserve(8);
|
||||
buf.extend(&[0xF2, 0x0F, 0x10, 0x05 | (dst_mod << 3)]);
|
||||
buf.extend([0xF2, 0x0F, 0x10, 0x05 | (dst_mod << 3)]);
|
||||
}
|
||||
buf.extend(&offset.to_le_bytes());
|
||||
buf.extend(offset.to_le_bytes());
|
||||
}
|
||||
|
||||
/// `MOVSD r/m64,xmm1` -> Move xmm1 to r/m64. where m64 references the base pointer.
|
||||
|
@ -2009,12 +2009,12 @@ fn movsd_base64_offset32_freg64(
|
|||
if src as u8 > 7 || base as u8 > 7 {
|
||||
buf.push(rex);
|
||||
}
|
||||
buf.extend(&[0x0F, 0x11, 0x80 | src_mod | base_mod]);
|
||||
buf.extend([0x0F, 0x11, 0x80 | src_mod | base_mod]);
|
||||
// Using RSP or R12 requires a secondary index byte.
|
||||
if base == X86_64GeneralReg::RSP || base == X86_64GeneralReg::R12 {
|
||||
buf.push(0x24);
|
||||
}
|
||||
buf.extend(&offset.to_le_bytes());
|
||||
buf.extend(offset.to_le_bytes());
|
||||
}
|
||||
|
||||
/// `MOVSD xmm1,r/m64` -> Move r/m64 to xmm1. where m64 references the base pointer.
|
||||
|
@ -2034,12 +2034,12 @@ fn movsd_freg64_base64_offset32(
|
|||
if dst as u8 > 7 || base as u8 > 7 {
|
||||
buf.push(rex);
|
||||
}
|
||||
buf.extend(&[0x0F, 0x10, 0x80 | dst_mod | base_mod]);
|
||||
buf.extend([0x0F, 0x10, 0x80 | dst_mod | base_mod]);
|
||||
// Using RSP or R12 requires a secondary index byte.
|
||||
if base == X86_64GeneralReg::RSP || base == X86_64GeneralReg::R12 {
|
||||
buf.push(0x24);
|
||||
}
|
||||
buf.extend(&offset.to_le_bytes());
|
||||
buf.extend(offset.to_le_bytes());
|
||||
}
|
||||
|
||||
/// `NEG r/m64` -> Two's complement negate r/m64.
|
||||
|
@ -2047,7 +2047,7 @@ fn movsd_freg64_base64_offset32(
|
|||
fn neg_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) {
|
||||
let rex = add_rm_extension(reg, REX_W);
|
||||
let reg_mod = reg as u8 % 8;
|
||||
buf.extend(&[rex, 0xF7, 0xD8 | reg_mod]);
|
||||
buf.extend([rex, 0xF7, 0xD8 | reg_mod]);
|
||||
}
|
||||
|
||||
// helper function for `set*` instructions
|
||||
|
@ -2060,10 +2060,10 @@ fn set_reg64_help(op_code: u8, buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) {
|
|||
let reg_mod = reg as u8 % 8;
|
||||
use X86_64GeneralReg::*;
|
||||
match reg {
|
||||
RAX | RCX | RDX | RBX => buf.extend(&[0x0F, op_code, 0xC0 | reg_mod]),
|
||||
RSP | RBP | RSI | RDI => buf.extend(&[REX, 0x0F, op_code, 0xC0 | reg_mod]),
|
||||
RAX | RCX | RDX | RBX => buf.extend([0x0F, op_code, 0xC0 | reg_mod]),
|
||||
RSP | RBP | RSI | RDI => buf.extend([REX, 0x0F, op_code, 0xC0 | reg_mod]),
|
||||
R8 | R9 | R10 | R11 | R12 | R13 | R14 | R15 => {
|
||||
buf.extend(&[REX | 1, 0x0F, op_code, 0xC0 | reg_mod])
|
||||
buf.extend([REX | 1, 0x0F, op_code, 0xC0 | reg_mod])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2085,7 +2085,7 @@ fn cvtsi2_help<T: RegTrait, U: RegTrait>(
|
|||
let mod1 = (dst.value() % 8) << 3;
|
||||
let mod2 = src.value() % 8;
|
||||
|
||||
buf.extend(&[op_code1, rex, 0x0F, op_code2, 0xC0 | mod1 | mod2])
|
||||
buf.extend([op_code1, rex, 0x0F, op_code2, 0xC0 | mod1 | mod2])
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -2099,7 +2099,7 @@ fn cvtsx2_help<T: RegTrait, V: RegTrait>(
|
|||
let mod1 = (dst.value() % 8) << 3;
|
||||
let mod2 = src.value() % 8;
|
||||
|
||||
buf.extend(&[op_code1, 0x0F, op_code2, 0xC0 | mod1 | mod2])
|
||||
buf.extend([op_code1, 0x0F, op_code2, 0xC0 | mod1 | mod2])
|
||||
}
|
||||
|
||||
/// `SETE r/m64` -> Set Byte on Condition - zero/equal (ZF=1)
|
||||
|
@ -2183,8 +2183,8 @@ fn sub_reg64_imm32(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, imm: i32) {
|
|||
let rex = add_rm_extension(dst, REX_W);
|
||||
let dst_mod = dst as u8 % 8;
|
||||
buf.reserve(7);
|
||||
buf.extend(&[rex, 0x81, 0xE8 | dst_mod]);
|
||||
buf.extend(&imm.to_le_bytes());
|
||||
buf.extend([rex, 0x81, 0xE8 | dst_mod]);
|
||||
buf.extend(imm.to_le_bytes());
|
||||
}
|
||||
|
||||
/// `SUB r/m64,r64` -> Sub r64 to r/m64.
|
||||
|
@ -2199,7 +2199,7 @@ fn pop_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) {
|
|||
let reg_mod = reg as u8 % 8;
|
||||
if reg as u8 > 7 {
|
||||
let rex = add_opcode_extension(reg, REX);
|
||||
buf.extend(&[rex, 0x58 | reg_mod]);
|
||||
buf.extend([rex, 0x58 | reg_mod]);
|
||||
} else {
|
||||
buf.push(0x58 | reg_mod);
|
||||
}
|
||||
|
@ -2211,7 +2211,7 @@ fn push_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) {
|
|||
let reg_mod = reg as u8 % 8;
|
||||
if reg as u8 > 7 {
|
||||
let rex = add_opcode_extension(reg, REX);
|
||||
buf.extend(&[rex, 0x50 | reg_mod]);
|
||||
buf.extend([rex, 0x50 | reg_mod]);
|
||||
} else {
|
||||
buf.push(0x50 | reg_mod);
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ trait Backend<'a> {
|
|||
let module_id = env.module_id;
|
||||
let ident_ids = interns.all_ident_ids.get_mut(&module_id).unwrap();
|
||||
|
||||
rc_proc_gen.expand_refcount_stmt(ident_ids, layout, modify, *following)
|
||||
rc_proc_gen.expand_refcount_stmt(ident_ids, layout, modify, following)
|
||||
};
|
||||
|
||||
for spec in new_specializations.into_iter() {
|
||||
|
|
|
@ -421,7 +421,7 @@ fn build_proc<'a, B: Backend<'a>>(
|
|||
}
|
||||
Relocation::LinkedFunction { offset, name } => {
|
||||
// If the symbol is an undefined roc function, we need to add it here.
|
||||
if output.symbol_id(name.as_bytes()) == None && name.starts_with("roc_") {
|
||||
if output.symbol_id(name.as_bytes()).is_none() && name.starts_with("roc_") {
|
||||
let builtin_symbol = Symbol {
|
||||
name: name.as_bytes().to_vec(),
|
||||
value: 0,
|
||||
|
@ -435,7 +435,7 @@ fn build_proc<'a, B: Backend<'a>>(
|
|||
output.add_symbol(builtin_symbol);
|
||||
}
|
||||
// If the symbol is an undefined reference counting procedure, we need to add it here.
|
||||
if output.symbol_id(name.as_bytes()) == None {
|
||||
if output.symbol_id(name.as_bytes()).is_none() {
|
||||
for (sym, rc_name) in rc_proc_names.iter() {
|
||||
if name == rc_name {
|
||||
let section_id = output.add_section(
|
||||
|
|
|
@ -411,16 +411,16 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
|
|||
match rc_operation {
|
||||
Mode::Inc => {
|
||||
let n = 1;
|
||||
increment_refcount_layout(env, function_value, layout_ids, n, value, layout);
|
||||
increment_refcount_layout(env, layout_ids, n, value, layout);
|
||||
}
|
||||
Mode::IncN => {
|
||||
let n = it.next().unwrap().into_int_value();
|
||||
n.set_name(Symbol::ARG_2.as_str(&env.interns));
|
||||
|
||||
increment_n_refcount_layout(env, function_value, layout_ids, n, value, layout);
|
||||
increment_n_refcount_layout(env, layout_ids, n, value, layout);
|
||||
}
|
||||
Mode::Dec => {
|
||||
decrement_refcount_layout(env, function_value, layout_ids, value, layout);
|
||||
decrement_refcount_layout(env, layout_ids, value, layout);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ impl<'ctx> Iterator for FunctionIterator<'ctx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq)]
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Scope<'a, 'ctx> {
|
||||
symbols: ImMap<Symbol, (Layout<'a>, BasicValueEnum<'ctx>)>,
|
||||
pub top_level_thunks: ImMap<Symbol, (ProcLayout<'a>, FunctionValue<'ctx>)>,
|
||||
|
@ -973,7 +973,7 @@ pub fn build_exp_literal<'a, 'ctx, 'env>(
|
|||
_ => unreachable!("incorrect small_str_bytes"),
|
||||
}
|
||||
} else {
|
||||
let ptr = define_global_str_literal_ptr(env, *str_literal);
|
||||
let ptr = define_global_str_literal_ptr(env, str_literal);
|
||||
let number_of_elements = env.ptr_int().const_int(str_literal.len() as u64, false);
|
||||
|
||||
let alloca =
|
||||
|
@ -2723,14 +2723,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
let layout = *layout;
|
||||
|
||||
if layout.contains_refcounted(env.layout_interner) {
|
||||
increment_refcount_layout(
|
||||
env,
|
||||
parent,
|
||||
layout_ids,
|
||||
*inc_amount,
|
||||
value,
|
||||
&layout,
|
||||
);
|
||||
increment_refcount_layout(env, layout_ids, *inc_amount, value, &layout);
|
||||
}
|
||||
|
||||
build_exp_stmt(env, layout_ids, func_spec_solutions, scope, parent, cont)
|
||||
|
@ -2739,7 +2732,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
let (value, layout) = load_symbol_and_layout(scope, symbol);
|
||||
|
||||
if layout.contains_refcounted(env.layout_interner) {
|
||||
decrement_refcount_layout(env, parent, layout_ids, value, layout);
|
||||
decrement_refcount_layout(env, layout_ids, value, layout);
|
||||
}
|
||||
|
||||
build_exp_stmt(env, layout_ids, func_spec_solutions, scope, parent, cont)
|
||||
|
@ -3847,12 +3840,9 @@ fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>(
|
|||
arg_type.into_pointer_type().get_element_type(),
|
||||
);
|
||||
// C return pointer goes at the beginning of params, and we must skip it if it exists.
|
||||
let param_index = (i
|
||||
+ (if matches!(cc_return, CCReturn::ByPointer) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
})) as u32;
|
||||
let returns_pointer = matches!(cc_return, CCReturn::ByPointer);
|
||||
let param_index = i as u32 + returns_pointer as u32;
|
||||
|
||||
c_function.add_attribute(AttributeLoc::Param(param_index), byval);
|
||||
c_function.add_attribute(AttributeLoc::Param(param_index), nonnull);
|
||||
}
|
||||
|
@ -4554,7 +4544,7 @@ fn build_procedures_help<'a, 'ctx, 'env>(
|
|||
fn_val.print_to_stderr();
|
||||
|
||||
if let Some(app_ll_file) = debug_output_file {
|
||||
env.module.print_to_file(&app_ll_file).unwrap();
|
||||
env.module.print_to_file(app_ll_file).unwrap();
|
||||
|
||||
panic!(
|
||||
r"😱 LLVM errors when defining function {:?}; I wrote the full LLVM IR to {:?}",
|
||||
|
@ -6209,14 +6199,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
|
||||
let element_layout = list_element_layout!(list_layout);
|
||||
|
||||
list_get_unsafe(
|
||||
env,
|
||||
layout_ids,
|
||||
parent,
|
||||
element_layout,
|
||||
elem_index,
|
||||
wrapper_struct,
|
||||
)
|
||||
list_get_unsafe(env, layout_ids, element_layout, elem_index, wrapper_struct)
|
||||
}
|
||||
ListReplaceUnsafe => {
|
||||
let list = load_symbol(scope, &args[0]);
|
||||
|
|
|
@ -121,7 +121,6 @@ pub(crate) fn list_with_capacity<'a, 'ctx, 'env>(
|
|||
pub(crate) fn list_get_unsafe<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
elem_index: IntValue<'ctx>,
|
||||
wrapper_struct: StructValue<'ctx>,
|
||||
|
@ -140,7 +139,7 @@ pub(crate) fn list_get_unsafe<'a, 'ctx, 'env>(
|
|||
|
||||
let result = load_roc_value(env, *element_layout, elem_ptr, "list_get_load_element");
|
||||
|
||||
increment_refcount_layout(env, parent, layout_ids, 1, result, element_layout);
|
||||
increment_refcount_layout(env, layout_ids, 1, result, element_layout);
|
||||
|
||||
result
|
||||
}
|
||||
|
|
|
@ -327,8 +327,6 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>(
|
|||
|
||||
arg_val.set_name(arg_symbol.as_str(&env.interns));
|
||||
|
||||
let parent = fn_val;
|
||||
|
||||
let wrapper_struct = arg_val.into_struct_value();
|
||||
|
||||
for (i, field_layout) in layouts.iter().enumerate() {
|
||||
|
@ -347,7 +345,6 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>(
|
|||
|
||||
modify_refcount_layout_help(
|
||||
env,
|
||||
parent,
|
||||
layout_ids,
|
||||
mode.to_call_mode(fn_val),
|
||||
when_recursive,
|
||||
|
@ -362,42 +359,32 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>(
|
|||
|
||||
pub fn increment_refcount_layout<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
inc_amount: u64,
|
||||
value: BasicValueEnum<'ctx>,
|
||||
layout: &Layout<'a>,
|
||||
) {
|
||||
let amount = env.ptr_int().const_int(inc_amount, false);
|
||||
increment_n_refcount_layout(env, parent, layout_ids, amount, value, layout);
|
||||
increment_n_refcount_layout(env, layout_ids, amount, value, layout);
|
||||
}
|
||||
|
||||
pub fn increment_n_refcount_layout<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
amount: IntValue<'ctx>,
|
||||
value: BasicValueEnum<'ctx>,
|
||||
layout: &Layout<'a>,
|
||||
) {
|
||||
modify_refcount_layout(
|
||||
env,
|
||||
parent,
|
||||
layout_ids,
|
||||
CallMode::Inc(amount),
|
||||
value,
|
||||
layout,
|
||||
);
|
||||
modify_refcount_layout(env, layout_ids, CallMode::Inc(amount), value, layout);
|
||||
}
|
||||
|
||||
pub fn decrement_refcount_layout<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
value: BasicValueEnum<'ctx>,
|
||||
layout: &Layout<'a>,
|
||||
) {
|
||||
modify_refcount_layout(env, parent, layout_ids, CallMode::Dec, value, layout);
|
||||
modify_refcount_layout(env, layout_ids, CallMode::Dec, value, layout);
|
||||
}
|
||||
|
||||
fn modify_refcount_builtin<'a, 'ctx, 'env>(
|
||||
|
@ -435,7 +422,6 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>(
|
|||
|
||||
fn modify_refcount_layout<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
call_mode: CallMode<'ctx>,
|
||||
value: BasicValueEnum<'ctx>,
|
||||
|
@ -443,7 +429,6 @@ fn modify_refcount_layout<'a, 'ctx, 'env>(
|
|||
) {
|
||||
modify_refcount_layout_help(
|
||||
env,
|
||||
parent,
|
||||
layout_ids,
|
||||
call_mode,
|
||||
&WhenRecursive::Unreachable,
|
||||
|
@ -460,7 +445,6 @@ enum WhenRecursive<'a> {
|
|||
|
||||
fn modify_refcount_layout_help<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
call_mode: CallMode<'ctx>,
|
||||
when_recursive: &WhenRecursive<'a>,
|
||||
|
@ -474,7 +458,6 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>(
|
|||
|
||||
let function = match modify_refcount_layout_build_function(
|
||||
env,
|
||||
parent,
|
||||
layout_ids,
|
||||
mode,
|
||||
when_recursive,
|
||||
|
@ -538,7 +521,6 @@ fn call_help<'a, 'ctx, 'env>(
|
|||
|
||||
fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
mode: Mode,
|
||||
when_recursive: &WhenRecursive<'a>,
|
||||
|
@ -603,7 +585,6 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
|||
|
||||
let function = modify_refcount_layout_build_function(
|
||||
env,
|
||||
parent,
|
||||
layout_ids,
|
||||
mode,
|
||||
when_recursive,
|
||||
|
@ -615,7 +596,6 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
|||
},
|
||||
LambdaSet(lambda_set) => modify_refcount_layout_build_function(
|
||||
env,
|
||||
parent,
|
||||
layout_ids,
|
||||
mode,
|
||||
when_recursive,
|
||||
|
@ -731,7 +711,6 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>(
|
|||
let loop_fn = |_index, element| {
|
||||
modify_refcount_layout_help(
|
||||
env,
|
||||
parent,
|
||||
layout_ids,
|
||||
mode.to_call_mode(fn_val),
|
||||
when_recursive,
|
||||
|
@ -1302,7 +1281,6 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
|||
for (field, field_layout) in deferred_nonrec {
|
||||
modify_refcount_layout_help(
|
||||
env,
|
||||
parent,
|
||||
layout_ids,
|
||||
mode.to_call_mode(decrement_fn),
|
||||
when_recursive,
|
||||
|
@ -1366,7 +1344,7 @@ fn union_layout_tags<'a>(
|
|||
match union_layout {
|
||||
NullableWrapped {
|
||||
other_tags: tags, ..
|
||||
} => *tags,
|
||||
} => tags,
|
||||
NullableUnwrapped { other_fields, .. } => arena.alloc([*other_fields]),
|
||||
NonNullableUnwrapped(fields) => arena.alloc([*fields]),
|
||||
Recursive(tags) => tags,
|
||||
|
@ -1687,7 +1665,6 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
|||
|
||||
modify_refcount_layout_help(
|
||||
env,
|
||||
parent,
|
||||
layout_ids,
|
||||
mode.to_call_mode(fn_val),
|
||||
when_recursive,
|
||||
|
@ -1709,7 +1686,6 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
|||
|
||||
modify_refcount_layout_help(
|
||||
env,
|
||||
parent,
|
||||
layout_ids,
|
||||
mode.to_call_mode(fn_val),
|
||||
when_recursive,
|
||||
|
|
|
@ -1237,7 +1237,7 @@ impl<'a> WasmBackend<'a> {
|
|||
}
|
||||
|
||||
CallType::HigherOrder(higher_order_lowlevel) => {
|
||||
call_higher_order_lowlevel(self, ret_sym, ret_layout, *higher_order_lowlevel)
|
||||
call_higher_order_lowlevel(self, ret_sym, ret_layout, higher_order_lowlevel)
|
||||
}
|
||||
|
||||
CallType::Foreign {
|
||||
|
|
|
@ -69,7 +69,7 @@ impl std::fmt::Debug for VmBlock<'_> {
|
|||
/// Rust representation matches Wasm encoding.
|
||||
/// It's an error to specify alignment higher than the "natural" alignment of the instruction
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd)]
|
||||
pub enum Align {
|
||||
Bytes1 = 0,
|
||||
Bytes2 = 1,
|
||||
|
@ -111,7 +111,7 @@ impl From<u32> for Align {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
||||
pub enum VmSymbolState {
|
||||
/// Value doesn't exist yet
|
||||
NotYetPushed,
|
||||
|
|
|
@ -303,7 +303,7 @@ impl<'a> Serialize for TypeSection<'a> {
|
|||
*
|
||||
*******************************************************************/
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum ImportDesc {
|
||||
Func { signature_index: u32 },
|
||||
Table { ty: TableType },
|
||||
|
@ -359,7 +359,7 @@ impl Serialize for ImportDesc {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Import<'a> {
|
||||
pub module: &'a str,
|
||||
pub name: &'a str,
|
||||
|
@ -551,7 +551,7 @@ impl Parse<()> for RefType {
|
|||
}
|
||||
}
|
||||
}
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct TableType {
|
||||
pub ref_type: RefType,
|
||||
pub limits: Limits,
|
||||
|
@ -659,7 +659,7 @@ impl Serialize for TableSection {
|
|||
*
|
||||
*******************************************************************/
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Limits {
|
||||
Min(u32),
|
||||
MinMax(u32, u32),
|
||||
|
@ -749,7 +749,7 @@ section_impl!(MemorySection, SectionId::Memory);
|
|||
*
|
||||
*******************************************************************/
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct GlobalType {
|
||||
pub value_type: ValueType,
|
||||
pub is_mutable: bool,
|
||||
|
|
|
@ -44,7 +44,7 @@ fn write_subs_for_module(module_id: ModuleId, filename: &str) {
|
|||
println!("cargo:rerun-if-changed={}", filepath.to_str().unwrap());
|
||||
|
||||
let mut output_path = PathBuf::from(std::env::var("OUT_DIR").unwrap());
|
||||
output_path.extend(&[filename]);
|
||||
output_path.extend([filename]);
|
||||
output_path.set_extension("dat");
|
||||
|
||||
#[cfg(not(windows))]
|
||||
|
@ -64,7 +64,7 @@ fn write_subs_for_module(module_id: ModuleId, filename: &str) {
|
|||
|
||||
fn write_types_for_module_dummy(output_path: &Path) {
|
||||
// write out a dummy file
|
||||
std::fs::write(output_path, &[]).unwrap();
|
||||
std::fs::write(output_path, []).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
|
@ -107,7 +107,7 @@ fn write_types_for_module_real(module_id: ModuleId, filename: &str, output_path:
|
|||
let abilities = module.abilities_store;
|
||||
let solved_implementations = module.resolved_implementations;
|
||||
|
||||
let mut file = std::fs::File::create(&output_path).unwrap();
|
||||
let mut file = std::fs::File::create(output_path).unwrap();
|
||||
|
||||
let type_state = TypeState {
|
||||
subs,
|
||||
|
|
|
@ -6,7 +6,7 @@ use crossbeam::thread;
|
|||
use parking_lot::Mutex;
|
||||
use roc_builtins::roc::module_source;
|
||||
use roc_can::abilities::{AbilitiesStore, PendingAbilitiesStore, ResolvedImpl};
|
||||
use roc_can::constraint::{Constraint as ConstraintSoa, Constraints};
|
||||
use roc_can::constraint::{Constraint as ConstraintSoa, Constraints, TypeOrVar};
|
||||
use roc_can::expr::PendingDerives;
|
||||
use roc_can::expr::{Declarations, ExpectLookup};
|
||||
use roc_can::module::{
|
||||
|
@ -3100,7 +3100,7 @@ fn load_platform_module<'a>(
|
|||
) -> Result<Msg<'a>, LoadingProblem<'a>> {
|
||||
let module_start_time = Instant::now();
|
||||
let file_io_start = Instant::now();
|
||||
let file = fs::read(&filename);
|
||||
let file = fs::read(filename);
|
||||
let file_io_duration = file_io_start.elapsed();
|
||||
|
||||
match file {
|
||||
|
@ -4262,10 +4262,11 @@ fn synth_list_len_type(subs: &mut Subs) -> Variable {
|
|||
|
||||
pub fn add_imports(
|
||||
my_module: ModuleId,
|
||||
constraints: &mut Constraints,
|
||||
subs: &mut Subs,
|
||||
mut pending_abilities: PendingAbilitiesStore,
|
||||
exposed_for_module: &ExposedForModule,
|
||||
def_types: &mut Vec<(Symbol, Loc<roc_types::types::Type>)>,
|
||||
def_types: &mut Vec<(Symbol, Loc<TypeOrVar>)>,
|
||||
rigid_vars: &mut Vec<Variable>,
|
||||
) -> (Vec<Variable>, AbilitiesStore) {
|
||||
use roc_types::types::Type;
|
||||
|
@ -4294,10 +4295,11 @@ pub fn add_imports(
|
|||
};
|
||||
|
||||
let copied_import = exposed_types.storage_subs.export_variable_to($subs, variable);
|
||||
let copied_import_index = constraints.push_type(Type::Variable(copied_import.variable));
|
||||
|
||||
def_types.push((
|
||||
$symbol,
|
||||
Loc::at_zero(Type::Variable(copied_import.variable)),
|
||||
Loc::at_zero(copied_import_index),
|
||||
));
|
||||
|
||||
// not a typo; rigids are turned into flex during type inference, but when imported we must
|
||||
|
@ -4327,12 +4329,10 @@ pub fn add_imports(
|
|||
// Patch used symbols from circular dependencies.
|
||||
if my_module == ModuleId::NUM {
|
||||
// Num needs List.len, but List imports Num.
|
||||
let list_len_type = synth_list_len_type(subs);
|
||||
def_types.push((
|
||||
Symbol::LIST_LEN,
|
||||
Loc::at_zero(Type::Variable(list_len_type)),
|
||||
));
|
||||
import_variables.push(list_len_type);
|
||||
let list_len_type_var = synth_list_len_type(subs);
|
||||
let list_len_type_index = constraints.push_type(Type::Variable(list_len_type_var));
|
||||
def_types.push((Symbol::LIST_LEN, Loc::at_zero(list_len_type_index)));
|
||||
import_variables.push(list_len_type_var);
|
||||
}
|
||||
|
||||
// Fill in the implementation information of the abilities from the modules we import, which we
|
||||
|
@ -4418,12 +4418,13 @@ fn run_solve_solve(
|
|||
} = module;
|
||||
|
||||
let mut rigid_vars: Vec<Variable> = Vec::new();
|
||||
let mut def_types: Vec<(Symbol, Loc<roc_types::types::Type>)> = Vec::new();
|
||||
let mut def_types: Vec<(Symbol, Loc<TypeOrVar>)> = Vec::new();
|
||||
|
||||
let mut subs = Subs::new_from_varstore(var_store);
|
||||
|
||||
let (import_variables, abilities_store) = add_imports(
|
||||
module.module_id,
|
||||
&mut constraints,
|
||||
&mut subs,
|
||||
pending_abilities,
|
||||
&exposed_for_module,
|
||||
|
|
|
@ -70,7 +70,7 @@ pub enum ArgSide {
|
|||
Right,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Associativity {
|
||||
/// left-associative operators:
|
||||
///
|
||||
|
|
|
@ -44,7 +44,7 @@ const SYMBOL_HAS_NICHE: () =
|
|||
// register_debug_idents calls (which should be made in debug mode).
|
||||
// Set it to false if you want to see the raw ModuleId and IdentId ints,
|
||||
// but please set it back to true before checking in the result!
|
||||
#[cfg(debug_assertions)]
|
||||
#[cfg(any(debug_assertions, feature = "debug-symbols"))]
|
||||
const PRETTY_PRINT_DEBUG_SYMBOLS: bool = true;
|
||||
|
||||
pub const DERIVABLE_ABILITIES: &[(Symbol, &[Symbol])] = &[
|
||||
|
@ -183,7 +183,7 @@ impl Symbol {
|
|||
///
|
||||
/// `Foo.bar`
|
||||
impl fmt::Debug for Symbol {
|
||||
#[cfg(debug_assertions)]
|
||||
#[cfg(any(debug_assertions, feature = "debug-symbols"))]
|
||||
#[allow(clippy::print_in_format_impl)]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if PRETTY_PRINT_DEBUG_SYMBOLS {
|
||||
|
@ -216,7 +216,7 @@ impl fmt::Debug for Symbol {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
#[cfg(not(any(debug_assertions, feature = "debug-symbols")))]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fallback_debug_fmt(*self, f)
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ fn fallback_debug_fmt(symbol: Symbol, f: &mut fmt::Formatter) -> fmt::Result {
|
|||
// end up using it in release builds anyway. Right? ...Right?
|
||||
lazy_static! {}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
#[cfg(any(debug_assertions, feature = "debug-symbols"))]
|
||||
lazy_static! {
|
||||
/// This is used in Debug builds only, to let us have a Debug instance
|
||||
/// which displays not only the Module ID, but also the Module Name which
|
||||
|
@ -399,7 +399,7 @@ impl fmt::Debug for ModuleId {
|
|||
/// needs a global mutex, so we don't do this in release builds. This means
|
||||
/// the Debug impl in release builds only shows the number, not the name (which
|
||||
/// it does not have available, due to having never stored it in the mutexed intern table.)
|
||||
#[cfg(debug_assertions)]
|
||||
#[cfg(any(debug_assertions, feature = "debug-symbols"))]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// Originally, this printed both name and numeric ID, but the numeric ID
|
||||
// didn't seem to add anything useful. Feel free to temporarily re-add it
|
||||
|
@ -425,7 +425,7 @@ impl fmt::Debug for ModuleId {
|
|||
}
|
||||
|
||||
/// In release builds, all we have access to is the number, so only display that.
|
||||
#[cfg(not(debug_assertions))]
|
||||
#[cfg(not(any(debug_assertions, feature = "debug-symbols")))]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
|
@ -470,7 +470,7 @@ impl<'a> PackageModuleIds<'a> {
|
|||
// didn't find it, so we'll add it
|
||||
let module_id = ModuleId::from_zero_indexed(self.by_id.len());
|
||||
self.by_id.push(module_name.clone());
|
||||
if cfg!(debug_assertions) {
|
||||
if cfg!(any(debug_assertions, feature = "debug-symbols")) {
|
||||
Self::insert_debug_name(module_id, module_name);
|
||||
}
|
||||
|
||||
|
@ -487,7 +487,7 @@ impl<'a> PackageModuleIds<'a> {
|
|||
ModuleIds { by_id }
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
#[cfg(any(debug_assertions, feature = "debug-symbols"))]
|
||||
fn insert_debug_name(module_id: ModuleId, module_name: &PQModuleName) {
|
||||
let mut names = DEBUG_MODULE_ID_NAMES.lock().expect("Failed to acquire lock for Debug interning into DEBUG_MODULE_ID_NAMES, presumably because a thread panicked.");
|
||||
|
||||
|
@ -503,7 +503,7 @@ impl<'a> PackageModuleIds<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
#[cfg(not(any(debug_assertions, feature = "debug-symbols")))]
|
||||
fn insert_debug_name(_module_id: ModuleId, _module_name: &PQModuleName) {
|
||||
// By design, this is a no-op in release builds!
|
||||
}
|
||||
|
@ -557,14 +557,14 @@ impl ModuleIds {
|
|||
// didn't find it, so we'll add it
|
||||
let module_id = ModuleId::from_zero_indexed(self.by_id.len());
|
||||
self.by_id.push(module_name.clone());
|
||||
if cfg!(debug_assertions) {
|
||||
if cfg!(any(debug_assertions, feature = "debug-symbols")) {
|
||||
Self::insert_debug_name(module_id, module_name);
|
||||
}
|
||||
|
||||
module_id
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
#[cfg(any(debug_assertions, feature = "debug-symbols"))]
|
||||
fn insert_debug_name(module_id: ModuleId, module_name: &ModuleName) {
|
||||
let mut names = DEBUG_MODULE_ID_NAMES.lock().expect("Failed to acquire lock for Debug interning into DEBUG_MODULE_ID_NAMES, presumably because a thread panicked.");
|
||||
|
||||
|
@ -574,7 +574,7 @@ impl ModuleIds {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
#[cfg(not(any(debug_assertions, feature = "debug-symbols")))]
|
||||
fn insert_debug_name(_module_id: ModuleId, _module_name: &ModuleName) {
|
||||
// By design, this is a no-op in release builds!
|
||||
}
|
||||
|
@ -868,7 +868,7 @@ macro_rules! define_builtins {
|
|||
IdentIds{ interner }
|
||||
};
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
if cfg!(any(debug_assertions, feature = "debug-symbols")) {
|
||||
let name = PQModuleName::Unqualified($module_name.into());
|
||||
PackageModuleIds::insert_debug_name(module_id, &name);
|
||||
module_id.register_debug_idents(&ident_ids);
|
||||
|
@ -910,7 +910,7 @@ macro_rules! define_builtins {
|
|||
let mut insert_both = |id: ModuleId, name_str: &'static str| {
|
||||
let name: ModuleName = name_str.into();
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
if cfg!(any(debug_assertions, feature = "debug-symbols")) {
|
||||
Self::insert_debug_name(id, &name);
|
||||
}
|
||||
|
||||
|
@ -936,7 +936,7 @@ macro_rules! define_builtins {
|
|||
let raw_name: IdentStr = name_str.into();
|
||||
let name = PQModuleName::Unqualified(raw_name.into());
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
if cfg!(any(debug_assertions, feature = "debug-symbols")) {
|
||||
Self::insert_debug_name(id, &name);
|
||||
}
|
||||
|
||||
|
|
|
@ -471,7 +471,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
) -> (bool, Vec<'a, Option<usize>>) {
|
||||
use UnionLayout::*;
|
||||
match union {
|
||||
NonRecursive(_) => return (false, bumpalo::vec![in self.arena]),
|
||||
NonRecursive(_) => (false, bumpalo::vec![in self.arena]),
|
||||
|
||||
Recursive(tags) => self.union_tail_recursion_fields_help(tags),
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use crate::ir::{
|
||||
BranchInfo, DestructType, Env, Expr, JoinPointId, Literal, Param, Pattern, Procs, Stmt,
|
||||
build_list_index_probe, BranchInfo, Call, CallType, DestructType, Env, Expr, JoinPointId,
|
||||
ListIndex, Literal, Param, Pattern, Procs, Stmt,
|
||||
};
|
||||
use crate::layout::{Builtin, Layout, LayoutCache, TagIdIntType, UnionLayout};
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_collections::all::{MutMap, MutSet};
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_exhaustive::{Ctor, CtorName, RenderAs, TagId, Union};
|
||||
use roc_exhaustive::{Ctor, CtorName, ListArity, RenderAs, TagId, Union};
|
||||
use roc_module::ident::TagName;
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::Symbol;
|
||||
|
@ -77,6 +78,12 @@ enum GuardedTest<'a> {
|
|||
Placeholder,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
|
||||
enum ListLenBound {
|
||||
Exact,
|
||||
AtLeast,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
enum Test<'a> {
|
||||
|
@ -95,6 +102,10 @@ enum Test<'a> {
|
|||
tag_id: TagIdIntType,
|
||||
num_alts: usize,
|
||||
},
|
||||
IsListLen {
|
||||
bound: ListLenBound,
|
||||
len: u64,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> Test<'a> {
|
||||
|
@ -110,6 +121,10 @@ impl<'a> Test<'a> {
|
|||
Test::IsStr(_) => false,
|
||||
Test::IsBit(_) => true,
|
||||
Test::IsByte { .. } => true,
|
||||
Test::IsListLen { bound, .. } => match bound {
|
||||
ListLenBound::Exact => true,
|
||||
ListLenBound::AtLeast => false,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -149,10 +164,13 @@ impl<'a> Hash for Test<'a> {
|
|||
num_alts.hash(state);
|
||||
}
|
||||
IsDecimal(v) => {
|
||||
// TODO: Is this okay?
|
||||
state.write_u8(6);
|
||||
v.hash(state);
|
||||
}
|
||||
IsListLen { len, bound } => {
|
||||
state.write_u8(7);
|
||||
(len, bound).hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -331,6 +349,11 @@ fn tests_are_complete_help(last_test: &Test, number_of_tests: usize) -> bool {
|
|||
Test::IsFloat(_, _) => false,
|
||||
Test::IsDecimal(_) => false,
|
||||
Test::IsStr(_) => false,
|
||||
Test::IsListLen {
|
||||
bound: ListLenBound::AtLeast,
|
||||
len: 0,
|
||||
} => true, // [..] test
|
||||
Test::IsListLen { .. } => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -578,6 +601,18 @@ fn test_at_path<'a>(
|
|||
arguments: arguments.to_vec(),
|
||||
},
|
||||
|
||||
List {
|
||||
arity,
|
||||
element_layout: _,
|
||||
elements: _,
|
||||
} => IsListLen {
|
||||
bound: match arity {
|
||||
ListArity::Exact(_) => ListLenBound::Exact,
|
||||
ListArity::Slice(_, _) => ListLenBound::AtLeast,
|
||||
},
|
||||
len: arity.min_len() as _,
|
||||
},
|
||||
|
||||
Voided { .. } => internal_error!("unreachable"),
|
||||
|
||||
OpaqueUnwrap { opaque, argument } => {
|
||||
|
@ -755,6 +790,37 @@ fn to_relevant_branch_help<'a>(
|
|||
_ => None,
|
||||
},
|
||||
|
||||
List {
|
||||
arity: my_arity,
|
||||
elements,
|
||||
element_layout: _,
|
||||
} => match test {
|
||||
IsListLen { bound: _, len } if my_arity.covers_length(*len as _) => {
|
||||
let sub_positions = elements.into_iter().enumerate().map(|(index, elem_pat)| {
|
||||
let mut new_path = path.to_vec();
|
||||
|
||||
let probe_index = ListIndex::from_pattern_index(index, my_arity);
|
||||
|
||||
let next_instr = PathInstruction::ListIndex {
|
||||
index: probe_index as _,
|
||||
};
|
||||
new_path.push(next_instr);
|
||||
|
||||
(new_path, elem_pat)
|
||||
});
|
||||
start.extend(sub_positions);
|
||||
start.extend(end);
|
||||
|
||||
Some(Branch {
|
||||
goal: branch.goal,
|
||||
guard: branch.guard.clone(),
|
||||
patterns: start,
|
||||
})
|
||||
}
|
||||
|
||||
_ => None,
|
||||
},
|
||||
|
||||
NewtypeDestructure {
|
||||
tag_name,
|
||||
arguments,
|
||||
|
@ -1021,7 +1087,8 @@ fn needs_tests(pattern: &Pattern) -> bool {
|
|||
| IntLiteral(_, _)
|
||||
| FloatLiteral(_, _)
|
||||
| DecimalLiteral(_)
|
||||
| StrLiteral(_) => true,
|
||||
| StrLiteral(_)
|
||||
| List { .. } => true,
|
||||
|
||||
Voided { .. } => internal_error!("unreachable"),
|
||||
}
|
||||
|
@ -1268,6 +1335,7 @@ pub fn optimize_when<'a>(
|
|||
enum PathInstruction {
|
||||
NewType,
|
||||
TagIndex { index: u64, tag_id: TagIdIntType },
|
||||
ListIndex { index: ListIndex },
|
||||
}
|
||||
|
||||
fn path_to_expr_help<'a>(
|
||||
|
@ -1337,19 +1405,46 @@ fn path_to_expr_help<'a>(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
PathInstruction::ListIndex { index } => {
|
||||
let list_sym = symbol;
|
||||
|
||||
match layout {
|
||||
Layout::Builtin(Builtin::List(elem_layout)) => {
|
||||
let (index_sym, new_stores) = build_list_index_probe(env, list_sym, index);
|
||||
|
||||
stores.extend(new_stores);
|
||||
|
||||
let load_sym = env.unique_symbol();
|
||||
let load_expr = Expr::Call(Call {
|
||||
call_type: CallType::LowLevel {
|
||||
op: LowLevel::ListGetUnsafe,
|
||||
update_mode: env.next_update_mode_id(),
|
||||
},
|
||||
arguments: env.arena.alloc([list_sym, index_sym]),
|
||||
});
|
||||
|
||||
stores.push((load_sym, *elem_layout, load_expr));
|
||||
|
||||
layout = *elem_layout;
|
||||
symbol = load_sym;
|
||||
}
|
||||
_ => internal_error!("not a list"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(symbol, stores, layout)
|
||||
}
|
||||
|
||||
fn test_to_equality<'a>(
|
||||
fn test_to_comparison<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
cond_symbol: Symbol,
|
||||
cond_layout: &Layout<'a>,
|
||||
path: &[PathInstruction],
|
||||
test: Test<'a>,
|
||||
) -> (StoresVec<'a>, Symbol, Symbol, Option<ConstructorKnown<'a>>) {
|
||||
) -> (StoresVec<'a>, Comparison, Option<ConstructorKnown<'a>>) {
|
||||
let (rhs_symbol, mut stores, test_layout) =
|
||||
path_to_expr_help(env, cond_symbol, path, *cond_layout);
|
||||
|
||||
|
@ -1379,8 +1474,7 @@ fn test_to_equality<'a>(
|
|||
|
||||
(
|
||||
stores,
|
||||
lhs_symbol,
|
||||
rhs_symbol,
|
||||
(lhs_symbol, Comparator::Eq, rhs_symbol),
|
||||
Some(ConstructorKnown::OnlyPass {
|
||||
scrutinee: path_symbol,
|
||||
layout: *cond_layout,
|
||||
|
@ -1397,7 +1491,7 @@ fn test_to_equality<'a>(
|
|||
let lhs_symbol = env.unique_symbol();
|
||||
stores.push((lhs_symbol, Layout::int_width(precision), lhs));
|
||||
|
||||
(stores, lhs_symbol, rhs_symbol, None)
|
||||
(stores, (lhs_symbol, Comparator::Eq, rhs_symbol), None)
|
||||
}
|
||||
|
||||
Test::IsFloat(test_int, precision) => {
|
||||
|
@ -1407,7 +1501,7 @@ fn test_to_equality<'a>(
|
|||
let lhs_symbol = env.unique_symbol();
|
||||
stores.push((lhs_symbol, Layout::float_width(precision), lhs));
|
||||
|
||||
(stores, lhs_symbol, rhs_symbol, None)
|
||||
(stores, (lhs_symbol, Comparator::Eq, rhs_symbol), None)
|
||||
}
|
||||
|
||||
Test::IsDecimal(test_dec) => {
|
||||
|
@ -1415,7 +1509,7 @@ fn test_to_equality<'a>(
|
|||
let lhs_symbol = env.unique_symbol();
|
||||
stores.push((lhs_symbol, *cond_layout, lhs));
|
||||
|
||||
(stores, lhs_symbol, rhs_symbol, None)
|
||||
(stores, (lhs_symbol, Comparator::Eq, rhs_symbol), None)
|
||||
}
|
||||
|
||||
Test::IsByte {
|
||||
|
@ -1427,7 +1521,7 @@ fn test_to_equality<'a>(
|
|||
let lhs_symbol = env.unique_symbol();
|
||||
stores.push((lhs_symbol, Layout::u8(), lhs));
|
||||
|
||||
(stores, lhs_symbol, rhs_symbol, None)
|
||||
(stores, (lhs_symbol, Comparator::Eq, rhs_symbol), None)
|
||||
}
|
||||
|
||||
Test::IsBit(test_bit) => {
|
||||
|
@ -1435,7 +1529,7 @@ fn test_to_equality<'a>(
|
|||
let lhs_symbol = env.unique_symbol();
|
||||
stores.push((lhs_symbol, Layout::Builtin(Builtin::Bool), lhs));
|
||||
|
||||
(stores, lhs_symbol, rhs_symbol, None)
|
||||
(stores, (lhs_symbol, Comparator::Eq, rhs_symbol), None)
|
||||
}
|
||||
|
||||
Test::IsStr(test_str) => {
|
||||
|
@ -1444,15 +1538,58 @@ fn test_to_equality<'a>(
|
|||
|
||||
stores.push((lhs_symbol, Layout::Builtin(Builtin::Str), lhs));
|
||||
|
||||
(stores, lhs_symbol, rhs_symbol, None)
|
||||
(stores, (lhs_symbol, Comparator::Eq, rhs_symbol), None)
|
||||
}
|
||||
|
||||
Test::IsListLen { bound, len } => {
|
||||
let list_layout = test_layout;
|
||||
let list_sym = rhs_symbol;
|
||||
|
||||
match list_layout {
|
||||
Layout::Builtin(Builtin::List(_elem_layout)) => {
|
||||
let real_len_expr = Expr::Call(Call {
|
||||
call_type: CallType::LowLevel {
|
||||
op: LowLevel::ListLen,
|
||||
update_mode: env.next_update_mode_id(),
|
||||
},
|
||||
arguments: env.arena.alloc([list_sym]),
|
||||
});
|
||||
let test_len_expr = Expr::Literal(Literal::Int((len as i128).to_ne_bytes()));
|
||||
|
||||
let real_len = env.unique_symbol();
|
||||
let test_len = env.unique_symbol();
|
||||
|
||||
let usize_layout = Layout::usize(env.target_info);
|
||||
|
||||
stores.push((real_len, usize_layout, real_len_expr));
|
||||
stores.push((test_len, usize_layout, test_len_expr));
|
||||
|
||||
let comparison = match bound {
|
||||
ListLenBound::Exact => (real_len, Comparator::Eq, test_len),
|
||||
ListLenBound::AtLeast => (real_len, Comparator::Geq, test_len),
|
||||
};
|
||||
|
||||
(stores, comparison, None)
|
||||
}
|
||||
_ => internal_error!(
|
||||
"test path is not a list: {:#?}",
|
||||
(cond_layout, test_layout, path)
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Comparator {
|
||||
Eq,
|
||||
Geq,
|
||||
}
|
||||
|
||||
type Comparison = (Symbol, Comparator, Symbol);
|
||||
|
||||
type Tests<'a> = std::vec::Vec<(
|
||||
bumpalo::collections::Vec<'a, (Symbol, Layout<'a>, Expr<'a>)>,
|
||||
Symbol,
|
||||
Symbol,
|
||||
Comparison,
|
||||
Option<ConstructorKnown<'a>>,
|
||||
)>;
|
||||
|
||||
|
@ -1466,17 +1603,25 @@ fn stores_and_condition<'a>(
|
|||
|
||||
// Assumption: there is at most 1 guard, and it is the outer layer.
|
||||
for (path, test) in test_chain {
|
||||
tests.push(test_to_equality(env, cond_symbol, cond_layout, &path, test))
|
||||
tests.push(test_to_comparison(
|
||||
env,
|
||||
cond_symbol,
|
||||
cond_layout,
|
||||
&path,
|
||||
test,
|
||||
))
|
||||
}
|
||||
|
||||
tests
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn compile_test<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
ret_layout: Layout<'a>,
|
||||
stores: bumpalo::collections::Vec<'a, (Symbol, Layout<'a>, Expr<'a>)>,
|
||||
lhs: Symbol,
|
||||
cmp: Comparator,
|
||||
rhs: Symbol,
|
||||
fail: &'a Stmt<'a>,
|
||||
cond: Stmt<'a>,
|
||||
|
@ -1487,6 +1632,7 @@ fn compile_test<'a>(
|
|||
ret_layout,
|
||||
stores,
|
||||
lhs,
|
||||
cmp,
|
||||
rhs,
|
||||
fail,
|
||||
cond,
|
||||
|
@ -1500,6 +1646,7 @@ fn compile_test_help<'a>(
|
|||
ret_layout: Layout<'a>,
|
||||
stores: bumpalo::collections::Vec<'a, (Symbol, Layout<'a>, Expr<'a>)>,
|
||||
lhs: Symbol,
|
||||
cmp: Comparator,
|
||||
rhs: Symbol,
|
||||
fail: &'a Stmt<'a>,
|
||||
mut cond: Stmt<'a>,
|
||||
|
@ -1560,7 +1707,10 @@ fn compile_test_help<'a>(
|
|||
default_branch,
|
||||
};
|
||||
|
||||
let op = LowLevel::Eq;
|
||||
let op = match cmp {
|
||||
Comparator::Eq => LowLevel::Eq,
|
||||
Comparator::Geq => LowLevel::NumGte,
|
||||
};
|
||||
let test = Expr::Call(crate::ir::Call {
|
||||
call_type: crate::ir::CallType::LowLevel {
|
||||
op,
|
||||
|
@ -1592,13 +1742,15 @@ fn compile_tests<'a>(
|
|||
fail: &'a Stmt<'a>,
|
||||
mut cond: Stmt<'a>,
|
||||
) -> Stmt<'a> {
|
||||
for (new_stores, lhs, rhs, opt_constructor_info) in tests.into_iter() {
|
||||
for (new_stores, (lhs, cmp, rhs), opt_constructor_info) in tests.into_iter() {
|
||||
match opt_constructor_info {
|
||||
None => {
|
||||
cond = compile_test(env, ret_layout, new_stores, lhs, rhs, fail, cond);
|
||||
cond = compile_test(env, ret_layout, new_stores, lhs, cmp, rhs, fail, cond);
|
||||
}
|
||||
Some(cinfo) => {
|
||||
cond = compile_test_help(env, cinfo, ret_layout, new_stores, lhs, rhs, fail, cond);
|
||||
cond = compile_test_help(
|
||||
env, cinfo, ret_layout, new_stores, lhs, cmp, rhs, fail, cond,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1781,7 +1933,7 @@ fn decide_to_branching<'a>(
|
|||
if number_of_tests == 1 {
|
||||
// if there is just one test, compile to a simple if-then-else
|
||||
|
||||
let (new_stores, lhs, rhs, _cinfo) = tests.into_iter().next().unwrap();
|
||||
let (new_stores, (lhs, cmp, rhs), _cinfo) = tests.into_iter().next().unwrap();
|
||||
|
||||
compile_test_help(
|
||||
env,
|
||||
|
@ -1789,6 +1941,7 @@ fn decide_to_branching<'a>(
|
|||
ret_layout,
|
||||
new_stores,
|
||||
lhs,
|
||||
cmp,
|
||||
rhs,
|
||||
fail,
|
||||
pass_expr,
|
||||
|
@ -1854,6 +2007,12 @@ fn decide_to_branching<'a>(
|
|||
Test::IsBit(v) => v as u64,
|
||||
Test::IsByte { tag_id, .. } => tag_id as u64,
|
||||
Test::IsCtor { tag_id, .. } => tag_id as u64,
|
||||
Test::IsListLen { len, bound } => match bound {
|
||||
ListLenBound::Exact => len as _,
|
||||
ListLenBound::AtLeast => {
|
||||
unreachable!("at-least bounds cannot be switched on")
|
||||
}
|
||||
},
|
||||
Test::IsDecimal(_) => unreachable!("decimals cannot be switched on"),
|
||||
Test::IsStr(_) => unreachable!("strings cannot be switched on"),
|
||||
};
|
||||
|
@ -1911,6 +2070,31 @@ fn decide_to_branching<'a>(
|
|||
union_layout.tag_id_layout(),
|
||||
env.arena.alloc(temp),
|
||||
)
|
||||
} else if let Layout::Builtin(Builtin::List(_)) = inner_cond_layout {
|
||||
let len_symbol = env.unique_symbol();
|
||||
|
||||
let switch = Stmt::Switch {
|
||||
cond_layout: Layout::usize(env.target_info),
|
||||
cond_symbol: len_symbol,
|
||||
branches: branches.into_bump_slice(),
|
||||
default_branch: (default_branch_info, env.arena.alloc(default_branch)),
|
||||
ret_layout,
|
||||
};
|
||||
|
||||
let len_expr = Expr::Call(Call {
|
||||
call_type: CallType::LowLevel {
|
||||
op: LowLevel::ListLen,
|
||||
update_mode: env.next_update_mode_id(),
|
||||
},
|
||||
arguments: env.arena.alloc([inner_cond_symbol]),
|
||||
});
|
||||
|
||||
Stmt::Let(
|
||||
len_symbol,
|
||||
len_expr,
|
||||
Layout::usize(env.target_info),
|
||||
env.arena.alloc(switch),
|
||||
)
|
||||
} else {
|
||||
Stmt::Switch {
|
||||
cond_layout: inner_cond_layout,
|
||||
|
|
|
@ -21,7 +21,7 @@ use roc_debug_flags::{
|
|||
};
|
||||
use roc_derive::SharedDerivedModule;
|
||||
use roc_error_macros::{internal_error, todo_abilities};
|
||||
use roc_exhaustive::{Ctor, CtorName, RenderAs, TagId};
|
||||
use roc_exhaustive::{Ctor, CtorName, ListArity, RenderAs, TagId};
|
||||
use roc_intern::Interner;
|
||||
use roc_late_solve::storage::{ExternalModuleStorage, ExternalModuleStorageSnapshot};
|
||||
use roc_late_solve::{resolve_ability_specialization, AbilitiesView, Resolved, UnificationFailed};
|
||||
|
@ -284,7 +284,7 @@ impl AbilityAliases {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum CapturedSymbols<'a> {
|
||||
None,
|
||||
Captured(&'a [(Symbol, Variable)]),
|
||||
|
@ -317,7 +317,7 @@ pub struct Proc<'a> {
|
|||
pub host_exposed_layouts: HostExposedLayouts<'a>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum HostExposedLayouts<'a> {
|
||||
NotHostExposed,
|
||||
HostExposed {
|
||||
|
@ -326,13 +326,13 @@ pub enum HostExposedLayouts<'a> {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum SelfRecursive {
|
||||
NotSelfRecursive,
|
||||
SelfRecursive(JoinPointId),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Parens {
|
||||
NotNeeded,
|
||||
InTypeParam,
|
||||
|
@ -847,6 +847,38 @@ struct SpecializationMark<'a> {
|
|||
function_mark: Option<RawFunctionLayout<'a>>,
|
||||
}
|
||||
|
||||
/// The deepest closure in the current stack of procedures under specialization a symbol specialization
|
||||
/// was used in.
|
||||
///
|
||||
/// This is necessary to understand what symbol specializations are used in what capture sets. For
|
||||
/// example, consider
|
||||
///
|
||||
/// main =
|
||||
/// x = 1
|
||||
///
|
||||
/// y = \{} -> 1u8 + x
|
||||
/// z = \{} -> 1u16 + x
|
||||
///
|
||||
/// Here, we have a two specializations of `x` to U8 and U16 with deepest uses of
|
||||
/// (2, y) and (2, z), respectively. This tells us that both of those specializations must be
|
||||
/// preserved by `main` (which is at depth 1), but that `y` and `z` respectively only need to
|
||||
/// capture one particular specialization of `x` each.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
struct UseDepth {
|
||||
depth: usize,
|
||||
symbol: Symbol,
|
||||
}
|
||||
|
||||
impl UseDepth {
|
||||
fn is_nested_use_in(&self, outer: &Self) -> bool {
|
||||
if self.symbol == outer.symbol {
|
||||
debug_assert!(self.depth == outer.depth);
|
||||
return true;
|
||||
}
|
||||
self.depth > outer.depth
|
||||
}
|
||||
}
|
||||
|
||||
/// When walking a function body, we may encounter specialized usages of polymorphic symbols. For
|
||||
/// example
|
||||
///
|
||||
|
@ -865,73 +897,10 @@ struct SymbolSpecializations<'a>(
|
|||
// 2. the number of specializations of a symbol in a def is even smaller (almost always only one)
|
||||
// So, a linear VecMap is preferrable. Use a two-layered one to make (1) extraction of defs easy
|
||||
// and (2) reads of a certain symbol be determined by its first occurrence, not its last.
|
||||
VecMap<Symbol, VecMap<SpecializationMark<'a>, (Variable, Symbol)>>,
|
||||
VecMap<Symbol, VecMap<SpecializationMark<'a>, (Variable, Symbol, UseDepth)>>,
|
||||
);
|
||||
|
||||
impl<'a> SymbolSpecializations<'a> {
|
||||
/// Gets a specialization for a symbol, or creates a new one.
|
||||
#[inline(always)]
|
||||
fn get_or_insert(
|
||||
&mut self,
|
||||
env: &mut Env<'a, '_>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
symbol: Symbol,
|
||||
specialization_var: Variable,
|
||||
) -> Symbol {
|
||||
let arena = env.arena;
|
||||
let subs: &Subs = env.subs;
|
||||
|
||||
let layout = match layout_cache.from_var(arena, specialization_var, subs) {
|
||||
Ok(layout) => layout,
|
||||
// This can happen when the def symbol has a type error. In such cases just use the
|
||||
// def symbol, which is erroring.
|
||||
Err(_) => return symbol,
|
||||
};
|
||||
|
||||
let is_closure = matches!(
|
||||
subs.get_content_without_compacting(specialization_var),
|
||||
Content::Structure(FlatType::Func(..))
|
||||
);
|
||||
let function_mark = if is_closure {
|
||||
let fn_layout = match layout_cache.raw_from_var(arena, specialization_var, subs) {
|
||||
Ok(layout) => layout,
|
||||
// This can happen when the def symbol has a type error. In such cases just use the
|
||||
// def symbol, which is erroring.
|
||||
Err(_) => return symbol,
|
||||
};
|
||||
Some(fn_layout)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let specialization_mark = SpecializationMark {
|
||||
layout,
|
||||
function_mark,
|
||||
};
|
||||
|
||||
let symbol_specializations = self.0.get_or_insert(symbol, Default::default);
|
||||
|
||||
// For the first specialization, always reuse the current symbol. The vast majority of defs
|
||||
// only have one instance type, so this preserves readability of the IR.
|
||||
// TODO: turn me off and see what breaks.
|
||||
let needs_fresh_symbol = !symbol_specializations.is_empty();
|
||||
|
||||
let mut make_specialized_symbol = || {
|
||||
if needs_fresh_symbol {
|
||||
env.unique_symbol()
|
||||
} else {
|
||||
symbol
|
||||
}
|
||||
};
|
||||
|
||||
let (_var, specialized_symbol) = symbol_specializations
|
||||
.get_or_insert(specialization_mark, || {
|
||||
(specialization_var, make_specialized_symbol())
|
||||
});
|
||||
|
||||
*specialized_symbol
|
||||
}
|
||||
|
||||
/// Inserts a known specialization for a symbol. Returns the overwritten specialization, if any.
|
||||
pub fn get_or_insert_known(
|
||||
&mut self,
|
||||
|
@ -939,17 +908,19 @@ impl<'a> SymbolSpecializations<'a> {
|
|||
mark: SpecializationMark<'a>,
|
||||
specialization_var: Variable,
|
||||
specialization_symbol: Symbol,
|
||||
) -> Option<(Variable, Symbol)> {
|
||||
self.0
|
||||
.get_or_insert(symbol, Default::default)
|
||||
.insert(mark, (specialization_var, specialization_symbol))
|
||||
deepest_use: UseDepth,
|
||||
) -> Option<(Variable, Symbol, UseDepth)> {
|
||||
self.0.get_or_insert(symbol, Default::default).insert(
|
||||
mark,
|
||||
(specialization_var, specialization_symbol, deepest_use),
|
||||
)
|
||||
}
|
||||
|
||||
/// Removes all specializations for a symbol, returning the type and symbol of each specialization.
|
||||
pub fn remove(
|
||||
&mut self,
|
||||
symbol: Symbol,
|
||||
) -> impl ExactSizeIterator<Item = (SpecializationMark<'a>, (Variable, Symbol))> {
|
||||
) -> impl ExactSizeIterator<Item = (SpecializationMark<'a>, (Variable, Symbol, UseDepth))> {
|
||||
self.0
|
||||
.remove(&symbol)
|
||||
.map(|(_, specializations)| specializations)
|
||||
|
@ -969,7 +940,7 @@ impl<'a> SymbolSpecializations<'a> {
|
|||
symbol
|
||||
);
|
||||
|
||||
specializations.next().map(|(_, (_, symbol))| symbol)
|
||||
specializations.next().map(|(_, (_, symbol, _))| symbol)
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
|
@ -987,6 +958,20 @@ pub struct ProcsBase<'a> {
|
|||
pub imported_module_thunks: &'a [Symbol],
|
||||
}
|
||||
|
||||
/// The current set of functions under specialization. They form a stack where the latest
|
||||
/// specialization to be seen is at the head of the stack.
|
||||
#[derive(Clone, Debug)]
|
||||
struct SpecializationStack<'a>(Vec<'a, Symbol>);
|
||||
|
||||
impl<'a> SpecializationStack<'a> {
|
||||
fn current_use_depth(&self) -> UseDepth {
|
||||
UseDepth {
|
||||
depth: self.0.len(),
|
||||
symbol: *self.0.last().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Procs<'a> {
|
||||
pub partial_procs: PartialProcs<'a>,
|
||||
|
@ -998,8 +983,7 @@ pub struct Procs<'a> {
|
|||
pub runtime_errors: BumpMap<Symbol, &'a str>,
|
||||
pub externals_we_need: BumpMap<ModuleId, ExternalSpecializations<'a>>,
|
||||
symbol_specializations: SymbolSpecializations<'a>,
|
||||
/// The current set of functions under specialization.
|
||||
pub specialization_stack: Vec<'a, Symbol>,
|
||||
specialization_stack: SpecializationStack<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Procs<'a> {
|
||||
|
@ -1014,17 +998,18 @@ impl<'a> Procs<'a> {
|
|||
runtime_errors: BumpMap::new_in(arena),
|
||||
externals_we_need: BumpMap::new_in(arena),
|
||||
symbol_specializations: Default::default(),
|
||||
specialization_stack: Vec::with_capacity_in(16, arena),
|
||||
specialization_stack: SpecializationStack(Vec::with_capacity_in(16, arena)),
|
||||
}
|
||||
}
|
||||
|
||||
fn push_active_specialization(&mut self, specialization: Symbol) {
|
||||
self.specialization_stack.push(specialization);
|
||||
self.specialization_stack.0.push(specialization);
|
||||
}
|
||||
|
||||
fn pop_active_specialization(&mut self, specialization: Symbol) {
|
||||
let popped = self
|
||||
.specialization_stack
|
||||
.0
|
||||
.pop()
|
||||
.expect("specialization stack is empty");
|
||||
debug_assert_eq!(
|
||||
|
@ -1049,7 +1034,7 @@ impl<'a> Procs<'a> {
|
|||
/// specialize both `foo : Str False -> Str` and `foo : {} False -> Str` at the same time, so
|
||||
/// the latter specialization must be deferred.
|
||||
fn symbol_needs_suspended_specialization(&self, specialization: Symbol) -> bool {
|
||||
self.specialization_stack.contains(&specialization)
|
||||
self.specialization_stack.0.contains(&specialization)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1368,6 +1353,94 @@ impl<'a> Procs<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a specialization for a symbol, or creates a new one.
|
||||
#[inline(always)]
|
||||
fn get_or_insert_symbol_specialization(
|
||||
&mut self,
|
||||
env: &mut Env<'a, '_>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
symbol: Symbol,
|
||||
specialization_var: Variable,
|
||||
) -> Symbol {
|
||||
let arena = env.arena;
|
||||
let subs: &Subs = env.subs;
|
||||
|
||||
let layout = match layout_cache.from_var(arena, specialization_var, subs) {
|
||||
Ok(layout) => layout,
|
||||
// This can happen when the def symbol has a type error. In such cases just use the
|
||||
// def symbol, which is erroring.
|
||||
Err(_) => return symbol,
|
||||
};
|
||||
|
||||
let is_closure = matches!(
|
||||
subs.get_content_without_compacting(specialization_var),
|
||||
Content::Structure(FlatType::Func(..))
|
||||
);
|
||||
let function_mark = if is_closure {
|
||||
let fn_layout = match layout_cache.raw_from_var(arena, specialization_var, subs) {
|
||||
Ok(layout) => layout,
|
||||
// This can happen when the def symbol has a type error. In such cases just use the
|
||||
// def symbol, which is erroring.
|
||||
Err(_) => return symbol,
|
||||
};
|
||||
Some(fn_layout)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let specialization_mark = SpecializationMark {
|
||||
layout,
|
||||
function_mark,
|
||||
};
|
||||
|
||||
let symbol_specializations = self
|
||||
.symbol_specializations
|
||||
.0
|
||||
.get_or_insert(symbol, Default::default);
|
||||
|
||||
// For the first specialization, always reuse the current symbol. The vast majority of defs
|
||||
// only have one instance type, so this preserves readability of the IR.
|
||||
// TODO: turn me off and see what breaks.
|
||||
let needs_fresh_symbol = !symbol_specializations.is_empty();
|
||||
|
||||
let mut make_specialized_symbol = || {
|
||||
if needs_fresh_symbol {
|
||||
env.unique_symbol()
|
||||
} else {
|
||||
symbol
|
||||
}
|
||||
};
|
||||
|
||||
let current_use = self.specialization_stack.current_use_depth();
|
||||
let (_var, specialized_symbol, deepest_use) = symbol_specializations
|
||||
.get_or_insert(specialization_mark, || {
|
||||
(specialization_var, make_specialized_symbol(), current_use)
|
||||
});
|
||||
|
||||
if deepest_use.is_nested_use_in(¤t_use) {
|
||||
*deepest_use = current_use;
|
||||
}
|
||||
|
||||
*specialized_symbol
|
||||
}
|
||||
|
||||
/// Get the symbol specializations used in the active specialization's body.
|
||||
pub fn get_symbol_specializations_used_in_body(
|
||||
&self,
|
||||
symbol: Symbol,
|
||||
) -> Option<impl Iterator<Item = (Variable, Symbol)> + '_> {
|
||||
let this_use = self.specialization_stack.current_use_depth();
|
||||
self.symbol_specializations.0.get(&symbol).map(move |l| {
|
||||
l.iter().filter_map(move |(_, (var, sym, deepest_use))| {
|
||||
if deepest_use.is_nested_use_in(&this_use) {
|
||||
Some((*var, *sym))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -1502,7 +1575,7 @@ impl<'a, 'i> Env<'a, 'i> {
|
|||
#[derive(Clone, Debug, PartialEq, Copy, Eq, Hash)]
|
||||
pub struct JoinPointId(pub Symbol);
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct Param<'a> {
|
||||
pub symbol: Symbol,
|
||||
pub borrow: bool,
|
||||
|
@ -1586,7 +1659,7 @@ pub enum Stmt<'a> {
|
|||
}
|
||||
|
||||
/// in the block below, symbol `scrutinee` is assumed be be of shape `tag_id`
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum BranchInfo<'a> {
|
||||
None,
|
||||
Constructor {
|
||||
|
@ -1629,7 +1702,7 @@ impl<'a> BranchInfo<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum ModifyRc {
|
||||
/// Increment a reference count
|
||||
Inc(Symbol, u64),
|
||||
|
@ -1775,7 +1848,7 @@ impl<'a> Call<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct CallSpecId {
|
||||
id: u32,
|
||||
}
|
||||
|
@ -1790,7 +1863,7 @@ impl CallSpecId {
|
|||
pub const BACKEND_DUMMY: Self = Self { id: 0 };
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct UpdateModeId {
|
||||
id: u32,
|
||||
}
|
||||
|
@ -1805,7 +1878,7 @@ impl UpdateModeId {
|
|||
pub const BACKEND_DUMMY: Self = Self { id: 0 };
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct UpdateModeIds {
|
||||
next: u32,
|
||||
}
|
||||
|
@ -1822,7 +1895,7 @@ impl UpdateModeIds {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum CallType<'a> {
|
||||
ByName {
|
||||
name: LambdaName<'a>,
|
||||
|
@ -1841,7 +1914,7 @@ pub enum CallType<'a> {
|
|||
HigherOrder(&'a HigherOrderLowLevel<'a>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct PassedFunction<'a> {
|
||||
/// name of the top-level function that is passed as an argument
|
||||
/// e.g. in `List.map xs Num.abs` this would be `Num.abs`
|
||||
|
@ -1858,7 +1931,7 @@ pub struct PassedFunction<'a> {
|
|||
pub owns_captured_environment: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct HigherOrderLowLevel<'a> {
|
||||
pub op: crate::low_level::HigherOrder,
|
||||
|
||||
|
@ -2503,7 +2576,7 @@ fn from_can_let<'a>(
|
|||
|
||||
// We do need specializations
|
||||
1 => {
|
||||
let (_specialization_mark, (var, specialized_symbol)) =
|
||||
let (_specialization_mark, (var, specialized_symbol, _deepest_use)) =
|
||||
needed_specializations.next().unwrap();
|
||||
|
||||
// Make sure rigid variables in the annotation are converted to flex variables.
|
||||
|
@ -2534,7 +2607,7 @@ fn from_can_let<'a>(
|
|||
|
||||
// Need to eat the cost and create a specialized version of the body for
|
||||
// each specialization.
|
||||
for (_specialization_mark, (var, specialized_symbol)) in
|
||||
for (_specialization_mark, (var, specialized_symbol, _deepest_use)) in
|
||||
needed_specializations
|
||||
{
|
||||
use roc_can::copy::deep_copy_type_vars_into_expr;
|
||||
|
@ -2703,7 +2776,7 @@ fn pattern_to_when<'a>(
|
|||
) -> (Symbol, Loc<roc_can::expr::Expr>) {
|
||||
use roc_can::expr::Expr::*;
|
||||
use roc_can::expr::{WhenBranch, WhenBranchPattern};
|
||||
use roc_can::pattern::Pattern::*;
|
||||
use roc_can::pattern::Pattern::{self, *};
|
||||
|
||||
match &pattern.value {
|
||||
Identifier(symbol) => (*symbol, body),
|
||||
|
@ -2766,6 +2839,8 @@ fn pattern_to_when<'a>(
|
|||
(symbol, Loc::at_zero(wrapped_body))
|
||||
}
|
||||
|
||||
Pattern::List { .. } => todo!(),
|
||||
|
||||
IntLiteral(..)
|
||||
| NumLiteral(..)
|
||||
| FloatLiteral(..)
|
||||
|
@ -3388,11 +3463,23 @@ fn specialize_proc_help<'a>(
|
|||
// An argument from the closure list may have taken on a specialized symbol
|
||||
// name during the evaluation of the def body. If this is the case, load the
|
||||
// specialized name rather than the original captured name!
|
||||
let mut get_specialized_name = |symbol| {
|
||||
procs
|
||||
.symbol_specializations
|
||||
.remove_single(symbol)
|
||||
.unwrap_or(symbol)
|
||||
let get_specialized_name = |symbol| {
|
||||
let specs_used_in_body =
|
||||
procs.get_symbol_specializations_used_in_body(symbol);
|
||||
|
||||
match specs_used_in_body {
|
||||
Some(mut specs) => {
|
||||
let spec_symbol =
|
||||
specs.next().map(|(_, sym)| sym).unwrap_or(symbol);
|
||||
if specs.next().is_some() {
|
||||
internal_error!(
|
||||
"polymorphic symbol captures not supported yet"
|
||||
);
|
||||
}
|
||||
spec_symbol
|
||||
}
|
||||
None => symbol,
|
||||
}
|
||||
};
|
||||
|
||||
match closure_layout
|
||||
|
@ -4083,9 +4170,7 @@ pub fn with_hole<'a>(
|
|||
variable,
|
||||
) {
|
||||
let real_symbol =
|
||||
procs
|
||||
.symbol_specializations
|
||||
.get_or_insert(env, layout_cache, symbol, variable);
|
||||
procs.get_or_insert_symbol_specialization(env, layout_cache, symbol, variable);
|
||||
symbol = real_symbol;
|
||||
}
|
||||
|
||||
|
@ -4182,7 +4267,7 @@ pub fn with_hole<'a>(
|
|||
match can_reuse_symbol(env, procs, &loc_arg_expr.value, arg_var) {
|
||||
// Opaques decay to their argument.
|
||||
ReuseSymbol::Value(symbol) => {
|
||||
let real_name = procs.symbol_specializations.get_or_insert(
|
||||
let real_name = procs.get_or_insert_symbol_specialization(
|
||||
env,
|
||||
layout_cache,
|
||||
symbol,
|
||||
|
@ -4247,7 +4332,7 @@ pub fn with_hole<'a>(
|
|||
can_fields.push(Field::FunctionOrUnspecialized(symbol, variable));
|
||||
}
|
||||
Value(symbol) => {
|
||||
let reusable = procs.symbol_specializations.get_or_insert(
|
||||
let reusable = procs.get_or_insert_symbol_specialization(
|
||||
env,
|
||||
layout_cache,
|
||||
symbol,
|
||||
|
@ -4722,6 +4807,7 @@ pub fn with_hole<'a>(
|
|||
find_lambda_name(env, layout_cache, lambda_set, name, &[]);
|
||||
construct_closure_data(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
lambda_set,
|
||||
lambda_name,
|
||||
|
@ -4775,6 +4861,7 @@ pub fn with_hole<'a>(
|
|||
find_lambda_name(env, layout_cache, lambda_set, name, &[]);
|
||||
construct_closure_data(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
lambda_set,
|
||||
lambda_name,
|
||||
|
@ -5023,6 +5110,7 @@ pub fn with_hole<'a>(
|
|||
|
||||
construct_closure_data(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
lambda_set,
|
||||
lambda_name,
|
||||
|
@ -5169,7 +5257,7 @@ pub fn with_hole<'a>(
|
|||
}
|
||||
}
|
||||
Value(function_symbol) => {
|
||||
let function_symbol = procs.symbol_specializations.get_or_insert(
|
||||
let function_symbol = procs.get_or_insert_symbol_specialization(
|
||||
env,
|
||||
layout_cache,
|
||||
function_symbol,
|
||||
|
@ -5585,7 +5673,8 @@ where
|
|||
#[allow(clippy::too_many_arguments)]
|
||||
fn construct_closure_data<'a, I>(
|
||||
env: &mut Env<'a, '_>,
|
||||
layout_cache: &LayoutCache<'a>,
|
||||
procs: &mut Procs<'a>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
lambda_set: LambdaSet<'a>,
|
||||
name: LambdaName<'a>,
|
||||
symbols: I,
|
||||
|
@ -5670,12 +5759,19 @@ where
|
|||
debug_assert_eq!(symbols.len(), 1);
|
||||
|
||||
let mut symbols = symbols;
|
||||
let (captured_symbol, _) = symbols.next().unwrap();
|
||||
let (captured_symbol, captured_var) = symbols.next().unwrap();
|
||||
|
||||
let captured_symbol = procs.get_or_insert_symbol_specialization(
|
||||
env,
|
||||
layout_cache,
|
||||
*captured_symbol,
|
||||
*captured_var,
|
||||
);
|
||||
|
||||
// The capture set is unwrapped, so just replaced the assigned capture symbol with the
|
||||
// only capture.
|
||||
let mut hole = hole.clone();
|
||||
substitute_in_exprs(env.arena, &mut hole, assigned, *captured_symbol);
|
||||
substitute_in_exprs(env.arena, &mut hole, assigned, captured_symbol);
|
||||
hole
|
||||
}
|
||||
ClosureRepresentation::EnumDispatch(repr) => match repr {
|
||||
|
@ -6056,6 +6152,7 @@ fn tag_union_to_function<'a>(
|
|||
debug_assert!(lambda_name.no_captures());
|
||||
construct_closure_data(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
lambda_set,
|
||||
lambda_name,
|
||||
|
@ -6388,7 +6485,7 @@ pub fn from_can<'a>(
|
|||
stmt = with_hole(
|
||||
env,
|
||||
loc_condition.value,
|
||||
variable,
|
||||
Variable::BOOL,
|
||||
procs,
|
||||
layout_cache,
|
||||
cond_symbol,
|
||||
|
@ -6444,7 +6541,7 @@ pub fn from_can<'a>(
|
|||
stmt = with_hole(
|
||||
env,
|
||||
loc_condition.value,
|
||||
variable,
|
||||
Variable::BOOL,
|
||||
procs,
|
||||
layout_cache,
|
||||
cond_symbol,
|
||||
|
@ -6912,7 +7009,7 @@ fn substitute_in_call<'a>(
|
|||
} => substitute(subs, name.name()).map(|new| CallType::ByName {
|
||||
name: name.replace_name(new),
|
||||
arg_layouts,
|
||||
ret_layout: *ret_layout,
|
||||
ret_layout,
|
||||
specialization_id: *specialization_id,
|
||||
}),
|
||||
CallType::Foreign { .. } => None,
|
||||
|
@ -7061,7 +7158,7 @@ fn substitute_in_expr<'a>(
|
|||
} => match substitute(subs, *structure) {
|
||||
Some(structure) => Some(StructAtIndex {
|
||||
index: *index,
|
||||
field_layouts: *field_layouts,
|
||||
field_layouts,
|
||||
structure,
|
||||
}),
|
||||
None => None,
|
||||
|
@ -7192,6 +7289,24 @@ fn store_pattern_help<'a>(
|
|||
stmt,
|
||||
);
|
||||
}
|
||||
|
||||
List {
|
||||
arity,
|
||||
element_layout,
|
||||
elements,
|
||||
} => {
|
||||
return store_list_pattern(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
outer_symbol,
|
||||
*arity,
|
||||
*element_layout,
|
||||
elements,
|
||||
stmt,
|
||||
)
|
||||
}
|
||||
|
||||
Voided { .. } => {
|
||||
return StorePattern::NotProductive(stmt);
|
||||
}
|
||||
|
@ -7264,6 +7379,190 @@ fn store_pattern_help<'a>(
|
|||
StorePattern::Productive(stmt)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) struct ListIndex(
|
||||
/// Positive if we should index from the head, negative if we should index from the tail
|
||||
/// 0 is lst[0]
|
||||
/// -1 is lst[List.len lst - 1]
|
||||
i64,
|
||||
);
|
||||
|
||||
impl ListIndex {
|
||||
pub fn from_pattern_index(index: usize, arity: ListArity) -> Self {
|
||||
match arity {
|
||||
ListArity::Exact(_) => Self(index as _),
|
||||
ListArity::Slice(head, tail) => {
|
||||
if index < head {
|
||||
Self(index as _)
|
||||
} else {
|
||||
// Slice(head=2, tail=5)
|
||||
//
|
||||
// s t ... w y z x q
|
||||
// 0 1 2 3 4 5 6 index
|
||||
// 0 1 2 3 4 (index - head)
|
||||
// 5 4 3 2 1 (tail - (index - head))
|
||||
Self(-((tail - (index - head)) as i64))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type Store<'a> = (Symbol, Layout<'a>, Expr<'a>);
|
||||
|
||||
/// Builds the list index we should index into
|
||||
#[must_use]
|
||||
pub(crate) fn build_list_index_probe<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
list_sym: Symbol,
|
||||
list_index: &ListIndex,
|
||||
) -> (Symbol, impl DoubleEndedIterator<Item = Store<'a>>) {
|
||||
let usize_layout = Layout::usize(env.target_info);
|
||||
|
||||
let list_index = list_index.0;
|
||||
let index_sym = env.unique_symbol();
|
||||
|
||||
let (opt_len_store, opt_offset_store, index_store) = if list_index >= 0 {
|
||||
let index_expr = Expr::Literal(Literal::Int((list_index as i128).to_ne_bytes()));
|
||||
|
||||
let index_store = (index_sym, usize_layout, index_expr);
|
||||
|
||||
(None, None, index_store)
|
||||
} else {
|
||||
let len_sym = env.unique_symbol();
|
||||
let len_expr = Expr::Call(Call {
|
||||
call_type: CallType::LowLevel {
|
||||
op: LowLevel::ListLen,
|
||||
update_mode: env.next_update_mode_id(),
|
||||
},
|
||||
arguments: env.arena.alloc([list_sym]),
|
||||
});
|
||||
|
||||
let offset = list_index.abs();
|
||||
let offset_sym = env.unique_symbol();
|
||||
let offset_expr = Expr::Literal(Literal::Int((offset as i128).to_ne_bytes()));
|
||||
|
||||
let index_expr = Expr::Call(Call {
|
||||
call_type: CallType::LowLevel {
|
||||
op: LowLevel::NumSub,
|
||||
update_mode: env.next_update_mode_id(),
|
||||
},
|
||||
arguments: env.arena.alloc([len_sym, offset_sym]),
|
||||
});
|
||||
|
||||
let len_store = (len_sym, usize_layout, len_expr);
|
||||
let offset_store = (offset_sym, usize_layout, offset_expr);
|
||||
let index_store = (index_sym, usize_layout, index_expr);
|
||||
|
||||
(Some(len_store), Some(offset_store), index_store)
|
||||
};
|
||||
|
||||
let stores = (opt_len_store.into_iter())
|
||||
.chain(opt_offset_store)
|
||||
.chain([index_store]);
|
||||
|
||||
(index_sym, stores)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn store_list_pattern<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
procs: &mut Procs<'a>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
list_sym: Symbol,
|
||||
list_arity: ListArity,
|
||||
element_layout: Layout<'a>,
|
||||
elements: &[Pattern<'a>],
|
||||
mut stmt: Stmt<'a>,
|
||||
) -> StorePattern<'a> {
|
||||
use Pattern::*;
|
||||
|
||||
let mut is_productive = false;
|
||||
|
||||
for (index, element) in elements.iter().enumerate().rev() {
|
||||
let compute_element_load = |env: &mut Env<'a, '_>| {
|
||||
let list_index = ListIndex::from_pattern_index(index, list_arity);
|
||||
|
||||
let (index_sym, needed_stores) = build_list_index_probe(env, list_sym, &list_index);
|
||||
|
||||
let load = Expr::Call(Call {
|
||||
call_type: CallType::LowLevel {
|
||||
op: LowLevel::ListGetUnsafe,
|
||||
update_mode: env.next_update_mode_id(),
|
||||
},
|
||||
arguments: env.arena.alloc([list_sym, index_sym]),
|
||||
});
|
||||
|
||||
(load, needed_stores)
|
||||
};
|
||||
|
||||
let (store_loaded, needed_stores) = match element {
|
||||
Identifier(symbol) => {
|
||||
let (load, needed_stores) = compute_element_load(env);
|
||||
|
||||
// Pattern can define only one specialization
|
||||
let symbol = procs
|
||||
.symbol_specializations
|
||||
.remove_single(*symbol)
|
||||
.unwrap_or(*symbol);
|
||||
|
||||
// store immediately in the given symbol
|
||||
(
|
||||
Stmt::Let(symbol, load, element_layout, env.arena.alloc(stmt)),
|
||||
needed_stores,
|
||||
)
|
||||
}
|
||||
Underscore
|
||||
| IntLiteral(_, _)
|
||||
| FloatLiteral(_, _)
|
||||
| DecimalLiteral(_)
|
||||
| EnumLiteral { .. }
|
||||
| BitLiteral { .. }
|
||||
| StrLiteral(_) => {
|
||||
// ignore
|
||||
continue;
|
||||
}
|
||||
_ => {
|
||||
// store the field in a symbol, and continue matching on it
|
||||
let symbol = env.unique_symbol();
|
||||
|
||||
// first recurse, continuing to unpack symbol
|
||||
match store_pattern_help(env, procs, layout_cache, element, symbol, stmt) {
|
||||
StorePattern::Productive(new) => {
|
||||
stmt = new;
|
||||
let (load, needed_stores) = compute_element_load(env);
|
||||
|
||||
// only if we bind one of its (sub)fields to a used name should we
|
||||
// extract the field
|
||||
(
|
||||
Stmt::Let(symbol, load, element_layout, env.arena.alloc(stmt)),
|
||||
needed_stores,
|
||||
)
|
||||
}
|
||||
StorePattern::NotProductive(new) => {
|
||||
// do nothing
|
||||
stmt = new;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
is_productive = true;
|
||||
|
||||
stmt = store_loaded;
|
||||
for (sym, lay, expr) in needed_stores.rev() {
|
||||
stmt = Stmt::Let(sym, expr, lay, env.arena.alloc(stmt));
|
||||
}
|
||||
}
|
||||
|
||||
if is_productive {
|
||||
StorePattern::Productive(stmt)
|
||||
} else {
|
||||
StorePattern::NotProductive(stmt)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn store_tag_pattern<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
|
@ -7586,9 +7885,7 @@ fn possible_reuse_symbol_or_specialize<'a>(
|
|||
) -> Symbol {
|
||||
match can_reuse_symbol(env, procs, expr, var) {
|
||||
ReuseSymbol::Value(symbol) => {
|
||||
procs
|
||||
.symbol_specializations
|
||||
.get_or_insert(env, layout_cache, symbol, var)
|
||||
procs.get_or_insert_symbol_specialization(env, layout_cache, symbol, var)
|
||||
}
|
||||
_ => env.unique_symbol(),
|
||||
}
|
||||
|
@ -7664,13 +7961,17 @@ where
|
|||
// captured symbols can only ever be specialized outside the closure.
|
||||
// After that is done, remove this hack.
|
||||
.chain(if no_specializations_needed {
|
||||
[Some((variable, left))]
|
||||
[Some((
|
||||
variable,
|
||||
left,
|
||||
procs.specialization_stack.current_use_depth(),
|
||||
))]
|
||||
} else {
|
||||
[None]
|
||||
})
|
||||
.flatten();
|
||||
|
||||
for (variable, left) in needed_specializations_of_left {
|
||||
for (variable, left, _deepest_use) in needed_specializations_of_left {
|
||||
add_needed_external(procs, env, variable, LambdaName::no_niche(right));
|
||||
|
||||
let res_layout = layout_cache.from_var(env.arena, variable, env.subs);
|
||||
|
@ -7694,7 +7995,7 @@ where
|
|||
|
||||
let left_had_specialization_symbols = needed_specializations_of_left.len() > 0;
|
||||
|
||||
for (specialization_mark, (specialized_var, specialized_sym)) in
|
||||
for (specialization_mark, (specialized_var, specialized_sym, deepest_use)) in
|
||||
needed_specializations_of_left
|
||||
{
|
||||
let old_specialized_sym = procs.symbol_specializations.get_or_insert_known(
|
||||
|
@ -7702,9 +8003,10 @@ where
|
|||
specialization_mark,
|
||||
specialized_var,
|
||||
specialized_sym,
|
||||
deepest_use,
|
||||
);
|
||||
|
||||
if let Some((_, old_specialized_sym)) = old_specialized_sym {
|
||||
if let Some((_, old_specialized_sym, _)) = old_specialized_sym {
|
||||
scratchpad_update_specializations.push((old_specialized_sym, specialized_sym));
|
||||
}
|
||||
}
|
||||
|
@ -7887,6 +8189,7 @@ fn specialize_symbol<'a>(
|
|||
|
||||
construct_closure_data(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
lambda_set,
|
||||
lambda_name,
|
||||
|
@ -7938,6 +8241,7 @@ fn specialize_symbol<'a>(
|
|||
|
||||
construct_closure_data(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
lambda_set,
|
||||
lambda_name,
|
||||
|
@ -8343,6 +8647,7 @@ fn call_by_name_help<'a>(
|
|||
|
||||
construct_closure_data(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
lambda_set,
|
||||
proc_name,
|
||||
|
@ -8739,6 +9044,7 @@ fn call_specialized_proc<'a>(
|
|||
|
||||
let result = construct_closure_data(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
lambda_set,
|
||||
proc_name,
|
||||
|
@ -8818,6 +9124,11 @@ pub enum Pattern<'a> {
|
|||
opaque: Symbol,
|
||||
argument: Box<(Pattern<'a>, Layout<'a>)>,
|
||||
},
|
||||
List {
|
||||
arity: ListArity,
|
||||
element_layout: Layout<'a>,
|
||||
elements: Vec<'a, Pattern<'a>>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> Pattern<'a> {
|
||||
|
@ -8854,6 +9165,7 @@ impl<'a> Pattern<'a> {
|
|||
stack.extend(arguments.iter().map(|(t, _)| t))
|
||||
}
|
||||
Pattern::OpaqueUnwrap { argument, .. } => stack.push(&argument.0),
|
||||
Pattern::List { elements, .. } => stack.extend(elements),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9604,6 +9916,35 @@ fn from_can_pattern_help<'a>(
|
|||
field_layouts.into_bump_slice(),
|
||||
))
|
||||
}
|
||||
|
||||
List {
|
||||
list_var: _,
|
||||
elem_var,
|
||||
patterns,
|
||||
} => {
|
||||
let element_layout = match layout_cache.from_var(env.arena, *elem_var, env.subs) {
|
||||
Ok(lay) => lay,
|
||||
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
|
||||
return Err(RuntimeError::UnresolvedTypeVar)
|
||||
}
|
||||
Err(LayoutProblem::Erroneous) => return Err(RuntimeError::ErroneousType),
|
||||
};
|
||||
|
||||
let arity = patterns.arity();
|
||||
|
||||
let mut mono_patterns = Vec::with_capacity_in(patterns.patterns.len(), env.arena);
|
||||
for loc_pat in patterns.patterns.iter() {
|
||||
let mono_pat =
|
||||
from_can_pattern_help(env, procs, layout_cache, &loc_pat.value, assignments)?;
|
||||
mono_patterns.push(mono_pat);
|
||||
}
|
||||
|
||||
Ok(Pattern::List {
|
||||
arity,
|
||||
element_layout,
|
||||
elements: mono_patterns,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use roc_module::symbol::Symbol;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum HigherOrder {
|
||||
ListMap {
|
||||
xs: Symbol,
|
||||
|
|
|
@ -128,7 +128,7 @@ fn function_s<'a, 'i>(
|
|||
remainder,
|
||||
} => {
|
||||
let id = *id;
|
||||
let body: &Stmt = *body;
|
||||
let body: &Stmt = body;
|
||||
let new_body = function_s(env, w, c, body);
|
||||
|
||||
let new_join = if std::ptr::eq(body, new_body) || body == new_body {
|
||||
|
@ -179,7 +179,7 @@ fn function_s<'a, 'i>(
|
|||
arena.alloc(new_switch)
|
||||
}
|
||||
Refcounting(op, continuation) => {
|
||||
let continuation: &Stmt = *continuation;
|
||||
let continuation: &Stmt = continuation;
|
||||
let new_continuation = function_s(env, w, c, continuation);
|
||||
|
||||
if std::ptr::eq(continuation, new_continuation) || continuation == new_continuation {
|
||||
|
@ -198,7 +198,7 @@ fn function_s<'a, 'i>(
|
|||
layouts,
|
||||
remainder,
|
||||
} => {
|
||||
let continuation: &Stmt = *remainder;
|
||||
let continuation: &Stmt = remainder;
|
||||
let new_continuation = function_s(env, w, c, continuation);
|
||||
|
||||
if std::ptr::eq(continuation, new_continuation) || continuation == new_continuation {
|
||||
|
@ -223,7 +223,7 @@ fn function_s<'a, 'i>(
|
|||
layouts,
|
||||
remainder,
|
||||
} => {
|
||||
let continuation: &Stmt = *remainder;
|
||||
let continuation: &Stmt = remainder;
|
||||
let new_continuation = function_s(env, w, c, continuation);
|
||||
|
||||
if std::ptr::eq(continuation, new_continuation) || continuation == new_continuation {
|
||||
|
|
|
@ -109,7 +109,7 @@ pub enum StrSegment<'a> {
|
|||
Interpolated(Loc<&'a Expr<'a>>), // e.g. (name) in "Hi, \(name)!"
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum EscapedChar {
|
||||
Newline, // \n
|
||||
Tab, // \t
|
||||
|
@ -581,7 +581,7 @@ pub enum AssignedField<'a, Val> {
|
|||
Malformed(&'a str),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum CommentOrNewline<'a> {
|
||||
Newline,
|
||||
LineComment(&'a str),
|
||||
|
@ -888,7 +888,7 @@ impl<'a, T> Collection<'a, T> {
|
|||
|
||||
pub fn final_comments(&self) -> &'a [CommentOrNewline<'a>] {
|
||||
if let Some(final_comments) = self.final_comments {
|
||||
*final_comments
|
||||
final_comments
|
||||
} else {
|
||||
&[]
|
||||
}
|
||||
|
|
|
@ -346,6 +346,7 @@ fn parse_expr_start<'a>(
|
|||
loc!(move |a, s, m| parse_expr_operator_chain(m, options, a, s)),
|
||||
fail_expr_start_e()
|
||||
]
|
||||
.trace("expr_start")
|
||||
.parse(arena, state, min_indent)
|
||||
}
|
||||
|
||||
|
@ -546,7 +547,7 @@ fn numeric_negate_expression<'a, T>(
|
|||
expr: Loc<Expr<'a>>,
|
||||
spaces: &'a [CommentOrNewline<'a>],
|
||||
) -> Loc<Expr<'a>> {
|
||||
debug_assert_eq!(state.bytes().get(0), Some(&b'-'));
|
||||
debug_assert_eq!(state.bytes().first(), Some(&b'-'));
|
||||
// for overflow reasons, we must make the unary minus part of the number literal.
|
||||
let start = state.pos();
|
||||
let region = Region::new(start, expr.region.end());
|
||||
|
@ -1933,7 +1934,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
|||
| Expr::UnaryOp(_, _) => Err(()),
|
||||
|
||||
Expr::Str(string) => Ok(Pattern::StrLiteral(*string)),
|
||||
Expr::SingleQuote(string) => Ok(Pattern::SingleQuote(*string)),
|
||||
Expr::SingleQuote(string) => Ok(Pattern::SingleQuote(string)),
|
||||
Expr::MalformedIdent(string, _problem) => Ok(Pattern::Malformed(string)),
|
||||
}
|
||||
}
|
||||
|
@ -2105,10 +2106,10 @@ mod when {
|
|||
parser::keyword_e(keyword::IS, EWhen::Is)
|
||||
)
|
||||
),
|
||||
move |arena, state, progress, (case_indent, loc_condition), min_indent| {
|
||||
move |arena, state, _progress, (case_indent, loc_condition), min_indent| {
|
||||
if case_indent < min_indent {
|
||||
return Err((
|
||||
progress,
|
||||
MadeProgress,
|
||||
// TODO maybe pass case_indent here?
|
||||
EWhen::PatternAlignment(5, state.pos()),
|
||||
state,
|
||||
|
@ -2118,15 +2119,18 @@ mod when {
|
|||
// Everything in the branches must be indented at least as much as the case itself.
|
||||
let min_indent = case_indent;
|
||||
|
||||
let (p1, branches, state) = branches(options).parse(arena, state, min_indent)?;
|
||||
let (_p1, branches, state) = branches(options)
|
||||
.parse(arena, state, min_indent)
|
||||
.map_err(|(_p, e, s)| (MadeProgress, e, s))?;
|
||||
|
||||
Ok((
|
||||
progress.or(p1),
|
||||
MadeProgress,
|
||||
Expr::When(arena.alloc(loc_condition), branches.into_bump_slice()),
|
||||
state,
|
||||
))
|
||||
},
|
||||
)
|
||||
.trace("when")
|
||||
}
|
||||
|
||||
/// Parsing when with indentation.
|
||||
|
|
|
@ -52,7 +52,7 @@ pub enum VersionComparison {
|
|||
DisallowsEqual,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct PackageName<'a>(&'a str);
|
||||
|
||||
impl<'a> PackageName<'a> {
|
||||
|
@ -160,7 +160,7 @@ pub struct HostedHeader<'a> {
|
|||
pub after_with: &'a [CommentOrNewline<'a>],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum To<'a> {
|
||||
ExistingPackage(&'a str),
|
||||
NewPackage(PackageName<'a>),
|
||||
|
@ -262,7 +262,7 @@ pub struct TypedIdent<'a> {
|
|||
pub ann: Loc<TypeAnnotation<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct PackageEntry<'a> {
|
||||
pub shorthand: &'a str,
|
||||
pub spaces_after_shorthand: &'a [CommentOrNewline<'a>],
|
||||
|
|
|
@ -737,6 +737,7 @@ pub trait Parser<'a, Output, Error> {
|
|||
) -> ParseResult<'a, Output, Error>;
|
||||
|
||||
#[cfg(not(feature = "parse_debug_trace"))]
|
||||
#[inline(always)]
|
||||
fn trace(self, _message: &'static str) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
|
@ -789,7 +790,7 @@ impl<'a, O: std::fmt::Debug, E: std::fmt::Debug, P: Parser<'a, O, E>> Parser<'a,
|
|||
where
|
||||
E: 'a,
|
||||
{
|
||||
fn parse(&self, arena: &'a Bump, state: State<'a>) -> ParseResult<'a, O, E> {
|
||||
fn parse(&self, arena: &'a Bump, state: State<'a>, min_indent: u32) -> ParseResult<'a, O, E> {
|
||||
use std::cell::RefCell;
|
||||
|
||||
thread_local! {
|
||||
|
@ -803,7 +804,7 @@ where
|
|||
let cur_indent = INDENT.with(|i| *i.borrow());
|
||||
|
||||
println!(
|
||||
"{:>5?}: {}{:<50}",
|
||||
"{:<5?}: {}{:<50}",
|
||||
state.pos(),
|
||||
&indent_text[..cur_indent * 2],
|
||||
self.message
|
||||
|
@ -1379,11 +1380,12 @@ macro_rules! and {
|
|||
macro_rules! one_of {
|
||||
($p1:expr, $p2:expr) => {
|
||||
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, min_indent: u32| {
|
||||
let original_state = state.clone();
|
||||
|
||||
match $p1.parse(arena, state, min_indent) {
|
||||
valid @ Ok(_) => valid,
|
||||
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state)),
|
||||
Err((NoProgress, _, state)) => $p2.parse(arena, state, min_indent),
|
||||
Err((NoProgress, _, _)) => $p2.parse(arena, original_state, min_indent),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -122,10 +122,7 @@ pub fn parse_single_quote<'a>() -> impl Parser<'a, &'a str, EString<'a>> {
|
|||
}
|
||||
}
|
||||
|
||||
fn consume_indent<'a>(
|
||||
mut state: State<'a>,
|
||||
mut indent: u32,
|
||||
) -> Result<State, (Progress, EString<'a>, State<'a>)> {
|
||||
fn consume_indent(mut state: State, mut indent: u32) -> Result<State, (Progress, EString, State)> {
|
||||
while indent > 0 {
|
||||
match state.bytes().first() {
|
||||
Some(b' ') => {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Expr(When(Arrow(@24), @24), @0)
|
|
@ -0,0 +1,6 @@
|
|||
when Just 4 is
|
||||
Just when ->
|
||||
4
|
||||
|
||||
_ ->
|
||||
2
|
|
@ -0,0 +1 @@
|
|||
Expr(When(Arrow(@26), @20), @0)
|
|
@ -0,0 +1,3 @@
|
|||
when 5 is
|
||||
1 -> 2
|
||||
_
|
|
@ -124,6 +124,8 @@ mod test_parse {
|
|||
fail/lambda_missing_indent.expr,
|
||||
fail/type_argument_no_arrow.expr,
|
||||
fail/type_double_comma.expr,
|
||||
fail/when_missing_arrow.expr,
|
||||
fail/pattern_binds_keyword.expr,
|
||||
pass/ability_demand_signature_is_multiline.expr,
|
||||
pass/ability_multi_line.expr,
|
||||
pass/ability_single_line.expr,
|
||||
|
|
|
@ -7,19 +7,19 @@ use roc_parse::pattern::PatternType;
|
|||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::types::AliasKind;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct CycleEntry {
|
||||
pub symbol: Symbol,
|
||||
pub symbol_region: Region,
|
||||
pub expr_region: Region,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum BadPattern {
|
||||
Unsupported(PatternType),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum ShadowKind {
|
||||
Variable,
|
||||
Alias(Symbol),
|
||||
|
@ -28,7 +28,7 @@ pub enum ShadowKind {
|
|||
}
|
||||
|
||||
/// Problems that can occur in the course of canonicalization.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Problem {
|
||||
UnusedDef(Symbol, Region),
|
||||
UnusedImport(Symbol, Region),
|
||||
|
@ -185,6 +185,9 @@ pub enum Problem {
|
|||
UnnecessaryOutputWildcard {
|
||||
region: Region,
|
||||
},
|
||||
MultipleListRestPattern {
|
||||
region: Region,
|
||||
},
|
||||
}
|
||||
|
||||
impl Problem {
|
||||
|
@ -313,6 +316,7 @@ impl Problem {
|
|||
def_pattern: region,
|
||||
..
|
||||
}
|
||||
| Problem::MultipleListRestPattern { region }
|
||||
| Problem::UnnecessaryOutputWildcard { region } => Some(*region),
|
||||
Problem::RuntimeError(RuntimeError::CircularDef(cycle_entries))
|
||||
| Problem::BadRecursion(cycle_entries) => {
|
||||
|
@ -330,13 +334,13 @@ impl Problem {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum ExtensionTypeKind {
|
||||
Record,
|
||||
TagUnion,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum PrecedenceProblem {
|
||||
BothNonAssociative(Region, Loc<BinOp>, Loc<BinOp>),
|
||||
}
|
||||
|
@ -385,7 +389,7 @@ pub enum FloatErrorKind {
|
|||
IntSuffix,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum RuntimeError {
|
||||
Shadowing {
|
||||
original_region: Region,
|
||||
|
@ -508,7 +512,7 @@ impl RuntimeError {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum MalformedPatternProblem {
|
||||
MalformedInt,
|
||||
MalformedFloat,
|
||||
|
@ -518,4 +522,5 @@ pub enum MalformedPatternProblem {
|
|||
BadIdent(roc_parse::ident::BadIdent),
|
||||
EmptySingleQuote,
|
||||
MultipleCharsInSingleQuote,
|
||||
DuplicateListRestPattern,
|
||||
}
|
||||
|
|
|
@ -133,7 +133,8 @@ impl Position {
|
|||
|
||||
impl Debug for Position {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "@{}", self.offset)
|
||||
write!(f, "@")?;
|
||||
self.offset.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ pub enum AbilityImplError {
|
|||
}
|
||||
|
||||
/// Indexes a requested deriving of an ability for an opaque type.
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct RequestedDeriveKey {
|
||||
pub opaque: Symbol,
|
||||
pub ability: Symbol,
|
||||
|
|
|
@ -947,15 +947,16 @@ fn solve(
|
|||
);
|
||||
|
||||
let expectation = &constraints.expectations[expectation_index.index()];
|
||||
let expected = type_cell_to_var(
|
||||
let expected = either_type_index_to_var(
|
||||
constraints,
|
||||
subs,
|
||||
rank,
|
||||
pools,
|
||||
problems,
|
||||
abilities_store,
|
||||
obligation_cache,
|
||||
pools,
|
||||
aliases,
|
||||
expectation.get_type_ref(),
|
||||
*expectation.get_type_ref(),
|
||||
);
|
||||
|
||||
match unify(
|
||||
|
@ -1065,15 +1066,16 @@ fn solve(
|
|||
let actual = deep_copy_var_in(subs, rank, pools, var, arena);
|
||||
let expectation = &constraints.expectations[expectation_index.index()];
|
||||
|
||||
let expected = type_cell_to_var(
|
||||
let expected = either_type_index_to_var(
|
||||
constraints,
|
||||
subs,
|
||||
rank,
|
||||
pools,
|
||||
problems,
|
||||
abilities_store,
|
||||
obligation_cache,
|
||||
pools,
|
||||
aliases,
|
||||
expectation.get_type_ref(),
|
||||
*expectation.get_type_ref(),
|
||||
);
|
||||
|
||||
match unify(
|
||||
|
@ -1178,15 +1180,16 @@ fn solve(
|
|||
);
|
||||
|
||||
let expectation = &constraints.pattern_expectations[expectation_index.index()];
|
||||
let expected = type_cell_to_var(
|
||||
let expected = either_type_index_to_var(
|
||||
constraints,
|
||||
subs,
|
||||
rank,
|
||||
pools,
|
||||
problems,
|
||||
abilities_store,
|
||||
obligation_cache,
|
||||
pools,
|
||||
aliases,
|
||||
expectation.get_type_ref(),
|
||||
*expectation.get_type_ref(),
|
||||
);
|
||||
|
||||
let mode = match constraint {
|
||||
|
@ -1487,15 +1490,16 @@ fn solve(
|
|||
// 4. Condition and branch types aren't "almost equal", this is just a normal type
|
||||
// error.
|
||||
|
||||
let (real_var, real_region, expected_type, category_and_expected) = match eq {
|
||||
let (real_var, real_region, branches_var, category_and_expected) = match eq {
|
||||
Ok(eq) => {
|
||||
let roc_can::constraint::Eq(real_var, expected, category, real_region) =
|
||||
constraints.eq[eq.index()];
|
||||
let expected = &constraints.expectations[expected.index()];
|
||||
|
||||
(
|
||||
real_var,
|
||||
real_region,
|
||||
expected.get_type_ref(),
|
||||
*expected.get_type_ref(),
|
||||
Ok((category, expected)),
|
||||
)
|
||||
}
|
||||
|
@ -1507,10 +1511,11 @@ fn solve(
|
|||
real_region,
|
||||
) = constraints.pattern_eq[peq.index()];
|
||||
let expected = &constraints.pattern_expectations[expected.index()];
|
||||
|
||||
(
|
||||
real_var,
|
||||
real_region,
|
||||
expected.get_type_ref(),
|
||||
*expected.get_type_ref(),
|
||||
Err((category, expected)),
|
||||
)
|
||||
}
|
||||
|
@ -1528,15 +1533,16 @@ fn solve(
|
|||
real_var,
|
||||
);
|
||||
|
||||
let branches_var = type_cell_to_var(
|
||||
let branches_var = either_type_index_to_var(
|
||||
constraints,
|
||||
subs,
|
||||
rank,
|
||||
pools,
|
||||
problems,
|
||||
abilities_store,
|
||||
obligation_cache,
|
||||
pools,
|
||||
aliases,
|
||||
expected_type,
|
||||
branches_var,
|
||||
);
|
||||
|
||||
let cond_source_is_likely_positive_value = category_and_expected.is_ok();
|
||||
|
@ -1736,24 +1742,28 @@ fn solve(
|
|||
close_pattern_matched_tag_unions(subs, real_var);
|
||||
}
|
||||
|
||||
let ExhaustiveSummary {
|
||||
if let Ok(ExhaustiveSummary {
|
||||
errors,
|
||||
exhaustive,
|
||||
redundancies,
|
||||
} = check(subs, real_var, sketched_rows, context);
|
||||
}) = check(subs, real_var, sketched_rows, context)
|
||||
{
|
||||
// Store information about whether the "when" is exhaustive, and
|
||||
// which (if any) of its branches are redundant. Codegen may use
|
||||
// this for branch-fixing and redundant elimination.
|
||||
if !exhaustive {
|
||||
exhaustive_mark.set_non_exhaustive(subs);
|
||||
}
|
||||
for redundant_mark in redundancies {
|
||||
redundant_mark.set_redundant(subs);
|
||||
}
|
||||
|
||||
// Store information about whether the "when" is exhaustive, and
|
||||
// which (if any) of its branches are redundant. Codegen may use
|
||||
// this for branch-fixing and redundant elimination.
|
||||
if !exhaustive {
|
||||
exhaustive_mark.set_non_exhaustive(subs);
|
||||
// Store the errors.
|
||||
problems.extend(errors.into_iter().map(TypeError::Exhaustive));
|
||||
} else {
|
||||
// Otherwise there were type errors deeper in the pattern; we will have
|
||||
// already reported them.
|
||||
}
|
||||
for redundant_mark in redundancies {
|
||||
redundant_mark.set_redundant(subs);
|
||||
}
|
||||
|
||||
// Store the errors.
|
||||
problems.extend(errors.into_iter().map(TypeError::Exhaustive));
|
||||
}
|
||||
|
||||
state
|
||||
|
@ -1892,6 +1902,11 @@ fn open_tag_union(subs: &mut Subs, var: Variable) {
|
|||
stack.extend(subs.get_subs_slice(fields.variables()));
|
||||
}
|
||||
|
||||
Structure(Apply(Symbol::LIST_LIST, args)) => {
|
||||
// Open up nested tag unions.
|
||||
stack.extend(subs.get_subs_slice(args));
|
||||
}
|
||||
|
||||
_ => {
|
||||
// Everything else is not a structural type that can be opened
|
||||
// (i.e. cannot be matched in a pattern-match)
|
||||
|
@ -1952,10 +1967,15 @@ fn close_pattern_matched_tag_unions(subs: &mut Subs, var: Variable) {
|
|||
}
|
||||
|
||||
Structure(Record(fields, _)) => {
|
||||
// Open up all nested tag unions.
|
||||
// Close up all nested tag unions.
|
||||
stack.extend(subs.get_subs_slice(fields.variables()));
|
||||
}
|
||||
|
||||
Structure(Apply(Symbol::LIST_LIST, args)) => {
|
||||
// Close up nested tag unions.
|
||||
stack.extend(subs.get_subs_slice(args));
|
||||
}
|
||||
|
||||
Alias(_, _, real_var, _) => {
|
||||
stack.push(real_var);
|
||||
}
|
||||
|
@ -2233,21 +2253,22 @@ impl LocalDefVarsVec<(Symbol, Loc<Variable>)> {
|
|||
subs: &mut Subs,
|
||||
def_types_slice: roc_can::constraint::DefTypes,
|
||||
) -> Self {
|
||||
let types_slice = &constraints.types[def_types_slice.types.indices()];
|
||||
let type_indices_slice = &constraints.type_slices[def_types_slice.types.indices()];
|
||||
let loc_symbols_slice = &constraints.loc_symbols[def_types_slice.loc_symbols.indices()];
|
||||
|
||||
let mut local_def_vars = Self::with_length(types_slice.len());
|
||||
let mut local_def_vars = Self::with_length(type_indices_slice.len());
|
||||
|
||||
for (&(symbol, region), typ_cell) in (loc_symbols_slice.iter()).zip(types_slice) {
|
||||
let var = type_cell_to_var(
|
||||
for (&(symbol, region), typ_index) in (loc_symbols_slice.iter()).zip(type_indices_slice) {
|
||||
let var = either_type_index_to_var(
|
||||
constraints,
|
||||
subs,
|
||||
rank,
|
||||
pools,
|
||||
problems,
|
||||
abilities_store,
|
||||
obligation_cache,
|
||||
pools,
|
||||
aliases,
|
||||
typ_cell,
|
||||
*typ_index,
|
||||
);
|
||||
|
||||
local_def_vars.push((symbol, Loc { value: var, region }));
|
||||
|
|
|
@ -4590,7 +4590,7 @@ mod solve_expr {
|
|||
removeHelp 1i64 Empty
|
||||
"#
|
||||
),
|
||||
"RBTree I64 I64",
|
||||
"RBTree (Key (Integer Signed64)) I64",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ pub enum TypeError {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub enum Unfulfilled {
|
||||
/// No claimed implementation of an ability for an opaque type.
|
||||
OpaqueDoesNotImplement { typ: Symbol, ability: Symbol },
|
||||
|
@ -51,7 +51,7 @@ pub enum Unfulfilled {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub enum UnderivableReason {
|
||||
NotABuiltin,
|
||||
/// The surface type is not derivable
|
||||
|
@ -60,7 +60,7 @@ pub enum UnderivableReason {
|
|||
NestedNotDerivable(ErrorType, NotDerivableContext),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub enum NotDerivableContext {
|
||||
NoContext,
|
||||
Function,
|
||||
|
@ -70,12 +70,12 @@ pub enum NotDerivableContext {
|
|||
Eq(NotDerivableEq),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub enum NotDerivableDecode {
|
||||
OptionalRecordField(Lowercase),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub enum NotDerivableEq {
|
||||
FloatingPoint,
|
||||
}
|
||||
|
|
|
@ -387,6 +387,7 @@ fn pattern<'a>(
|
|||
)
|
||||
.append(f.text("}"))
|
||||
.group(),
|
||||
List { .. } => todo!(),
|
||||
NumLiteral(_, n, _, _) | IntLiteral(_, _, n, _, _) | FloatLiteral(_, _, n, _, _) => {
|
||||
f.text(&**n)
|
||||
}
|
||||
|
|
|
@ -375,6 +375,7 @@ fn check_derived_typechecks_and_golden(
|
|||
let mut rigid_vars = Default::default();
|
||||
let (import_variables, abilities_store) = add_imports(
|
||||
test_module,
|
||||
&mut constraints,
|
||||
&mut test_subs,
|
||||
pending_abilities,
|
||||
&exposed_for_module,
|
||||
|
|
|
@ -11,6 +11,7 @@ path = "src/tests.rs"
|
|||
|
||||
[build-dependencies]
|
||||
roc_builtins = { path = "../builtins" }
|
||||
roc_utils = { path = "../../utils" }
|
||||
wasi_libc_sys = { path = "../../wasi-libc-sys" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -25,6 +26,7 @@ roc_types = { path = "../types" }
|
|||
roc_builtins = { path = "../builtins" }
|
||||
roc_constrain = { path = "../constrain" }
|
||||
roc_unify = { path = "../unify" }
|
||||
roc_utils = { path = "../../utils" }
|
||||
roc_solve = { path = "../solve" }
|
||||
roc_mono = { path = "../mono" }
|
||||
roc_reporting = { path = "../../reporting" }
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use roc_builtins::bitcode;
|
||||
use roc_utils::zig;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
use wasi_libc_sys::{WASI_COMPILER_RT_PATH, WASI_LIBC_PATH};
|
||||
|
||||
|
@ -113,13 +113,6 @@ fn build_wasm_test_host() {
|
|||
]);
|
||||
}
|
||||
|
||||
fn zig_executable() -> String {
|
||||
match std::env::var("ROC_ZIG") {
|
||||
Ok(path) => path,
|
||||
Err(_) => "zig".into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_wasm_platform(out_dir: &str, source_path: &str) -> PathBuf {
|
||||
let mut outfile = PathBuf::from(out_dir).join(PLATFORM_FILENAME);
|
||||
outfile.set_extension("o");
|
||||
|
@ -146,16 +139,25 @@ fn feature_is_enabled(feature_name: &str) -> bool {
|
|||
|
||||
// Run cargo with -vv to see commands printed out
|
||||
fn run_zig(args: &[&str]) {
|
||||
let zig = zig_executable();
|
||||
println!("{} {}", zig, args.join(" "));
|
||||
let output = Command::new(&zig).args(args).output().unwrap();
|
||||
let mut zig_cmd = zig();
|
||||
|
||||
if !output.status.success() {
|
||||
eprintln!("stdout:\n{}", String::from_utf8_lossy(&output.stdout));
|
||||
eprintln!("stderr:\n{}", String::from_utf8_lossy(&output.stderr));
|
||||
panic!("zig call failed with status {:?}", output.status);
|
||||
let full_zig_cmd = zig_cmd.args(args);
|
||||
println!("{:?}", full_zig_cmd);
|
||||
|
||||
let zig_cmd_output = full_zig_cmd.output().unwrap();
|
||||
|
||||
if !zig_cmd_output.status.success() {
|
||||
eprintln!(
|
||||
"stdout:\n{}",
|
||||
String::from_utf8_lossy(&zig_cmd_output.stdout)
|
||||
);
|
||||
eprintln!(
|
||||
"stderr:\n{}",
|
||||
String::from_utf8_lossy(&zig_cmd_output.stderr)
|
||||
);
|
||||
panic!("zig call failed with status {:?}", zig_cmd_output.status);
|
||||
}
|
||||
|
||||
assert!(output.stdout.is_empty(), "{:#?}", output);
|
||||
assert!(output.stderr.is_empty(), "{:#?}", output);
|
||||
assert!(zig_cmd_output.stdout.is_empty(), "{:#?}", zig_cmd_output);
|
||||
assert!(zig_cmd_output.stderr.is_empty(), "{:#?}", zig_cmd_output);
|
||||
}
|
||||
|
|
|
@ -3578,3 +3578,135 @@ fn list_walk_from_even_prefix_sum() {
|
|||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
mod pattern_match {
|
||||
#[cfg(feature = "gen-llvm")]
|
||||
use crate::helpers::llvm::assert_evals_to;
|
||||
|
||||
#[cfg(feature = "gen-wasm")]
|
||||
use crate::helpers::wasm::assert_evals_to;
|
||||
|
||||
use super::RocList;
|
||||
|
||||
#[test]
|
||||
fn unary_exact_size_match() {
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
helper = \l -> when l is
|
||||
[] -> 1u8
|
||||
_ -> 2u8
|
||||
|
||||
[ helper [], helper [{}] ]
|
||||
"#,
|
||||
RocList::from_slice(&[1, 2]),
|
||||
RocList<u8>
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_exact_size_match() {
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
helper = \l -> when l is
|
||||
[] -> 1u8
|
||||
[_] -> 2u8
|
||||
[_, _] -> 3u8
|
||||
[_, _, _] -> 4u8
|
||||
_ -> 5u8
|
||||
|
||||
[ helper [], helper [{}], helper [{}, {}], helper [{}, {}, {}], helper [{}, {}, {}, {}] ]
|
||||
"#,
|
||||
RocList::from_slice(&[1, 2, 3, 4, 5]),
|
||||
RocList<u8>
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ranged_matches_head() {
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
helper = \l -> when l is
|
||||
[] -> 1u8
|
||||
[A] -> 2u8
|
||||
[A, A, ..] -> 3u8
|
||||
[A, B, ..] -> 4u8
|
||||
[B, ..] -> 5u8
|
||||
|
||||
[
|
||||
helper [],
|
||||
helper [A],
|
||||
helper [A, A], helper [A, A, A], helper [A, A, B], helper [A, A, B, A],
|
||||
helper [A, B], helper [A, B, A], helper [A, B, B], helper [A, B, A, B],
|
||||
helper [B], helper [B, A], helper [B, B], helper [B, A, B, B],
|
||||
]
|
||||
"#,
|
||||
RocList::from_slice(&[
|
||||
1, //
|
||||
2, //
|
||||
3, 3, 3, 3, //
|
||||
4, 4, 4, 4, //
|
||||
5, 5, 5, 5, //
|
||||
]),
|
||||
RocList<u8>
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ranged_matches_tail() {
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
helper = \l -> when l is
|
||||
[] -> 1u8
|
||||
[A] -> 2u8
|
||||
[.., A, A] -> 3u8
|
||||
[.., B, A] -> 4u8
|
||||
[.., B] -> 5u8
|
||||
|
||||
[
|
||||
helper [],
|
||||
helper [A],
|
||||
helper [A, A], helper [A, A, A], helper [B, A, A], helper [A, B, A, A],
|
||||
helper [B, A], helper [A, B, A], helper [B, B, A], helper [B, A, B, A],
|
||||
helper [B], helper [A, B], helper [B, B], helper [B, A, B, B],
|
||||
]
|
||||
"#,
|
||||
RocList::from_slice(&[
|
||||
1, //
|
||||
2, //
|
||||
3, 3, 3, 3, //
|
||||
4, 4, 4, 4, //
|
||||
5, 5, 5, 5, //
|
||||
]),
|
||||
RocList<u8>
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bind_variables() {
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
helper : List U16 -> U16
|
||||
helper = \l -> when l is
|
||||
[] -> 1
|
||||
[x] -> x
|
||||
[.., w, x, y, z] -> w * x * y * z
|
||||
[x, y, ..] -> x * y
|
||||
|
||||
[
|
||||
helper [],
|
||||
helper [5],
|
||||
helper [3, 5], helper [3, 5, 7],
|
||||
helper [2, 3, 5, 7], helper [11, 2, 3, 5, 7], helper [13, 11, 2, 3, 5, 7],
|
||||
]
|
||||
"#,
|
||||
RocList::from_slice(&[
|
||||
1, //
|
||||
5, //
|
||||
15, 15, //
|
||||
210, 210, 210, //
|
||||
]),
|
||||
RocList<u16>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4104,3 +4104,25 @@ fn issue_4348() {
|
|||
RocStr
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn issue_4349() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
ir = Ok ""
|
||||
res =
|
||||
Result.try ir \_ ->
|
||||
when ir is
|
||||
Ok "" -> Ok ""
|
||||
_ -> Err Bad
|
||||
when res is
|
||||
Ok _ -> "okay"
|
||||
_ -> "FAIL"
|
||||
"#
|
||||
),
|
||||
RocStr::from("okay"),
|
||||
RocStr
|
||||
);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ use roc_load::{EntryPoint, ExecutionMode, LoadConfig, Threading};
|
|||
use roc_mono::ir::OptLevel;
|
||||
use roc_region::all::LineInfo;
|
||||
use roc_reporting::report::RenderTarget;
|
||||
use roc_utils::zig;
|
||||
use target_lexicon::Triple;
|
||||
|
||||
#[cfg(feature = "gen-llvm-wasm")]
|
||||
|
@ -340,11 +341,11 @@ fn annotate_with_debug_info<'ctx>(
|
|||
let app_bc_file = "/tmp/roc-debugir.bc";
|
||||
|
||||
// write the ll code to a file, so we can modify it
|
||||
module.print_to_file(&app_ll_file).unwrap();
|
||||
module.print_to_file(app_ll_file).unwrap();
|
||||
|
||||
// run the debugir https://github.com/vaivaswatha/debugir tool
|
||||
match Command::new("debugir")
|
||||
.args(&["-instnamer", app_ll_file])
|
||||
.args(["-instnamer", app_ll_file])
|
||||
.output()
|
||||
{
|
||||
Ok(_) => {}
|
||||
|
@ -360,11 +361,11 @@ fn annotate_with_debug_info<'ctx>(
|
|||
}
|
||||
|
||||
Command::new("llvm-as")
|
||||
.args(&[app_dbg_ll_file, "-o", app_bc_file])
|
||||
.args([app_dbg_ll_file, "-o", app_bc_file])
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
inkwell::module::Module::parse_bitcode_from_path(&app_bc_file, context).unwrap()
|
||||
inkwell::module::Module::parse_bitcode_from_path(app_bc_file, context).unwrap()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
@ -456,11 +457,9 @@ fn llvm_module_to_wasm_file(
|
|||
.write_to_file(llvm_module, file_type, &test_a_path)
|
||||
.unwrap();
|
||||
|
||||
use std::process::Command;
|
||||
|
||||
let output = Command::new(&crate::helpers::zig_executable())
|
||||
let output = zig()
|
||||
.current_dir(dir_path)
|
||||
.args(&[
|
||||
.args([
|
||||
"wasm-ld",
|
||||
concat!(env!("OUT_DIR"), "/wasm_test_platform.wasm"),
|
||||
test_a_path.to_str().unwrap(),
|
||||
|
|
|
@ -10,14 +10,6 @@ pub mod llvm;
|
|||
#[cfg(any(feature = "gen-wasm", feature = "gen-llvm-wasm"))]
|
||||
pub mod wasm;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn zig_executable() -> String {
|
||||
match std::env::var("ROC_ZIG") {
|
||||
Ok(path) => path,
|
||||
Err(_) => "zig".into(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn src_hash(src: &str) -> u64 {
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
|
|
|
@ -11,7 +11,7 @@ path = "src/tests.rs"
|
|||
|
||||
[dev-dependencies]
|
||||
roc_collections = { path = "../collections" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_module = { path = "../module", features = ["debug-symbols"] }
|
||||
roc_builtins = { path = "../builtins" }
|
||||
roc_load = { path = "../load" }
|
||||
roc_can = { path = "../can" }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
procedure List.5 (#Attr.2, #Attr.3):
|
||||
let List.380 : List {} = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.2 #Attr.3;
|
||||
let List.409 : List {} = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.2 #Attr.3;
|
||||
decref #Attr.2;
|
||||
ret List.380;
|
||||
ret List.409;
|
||||
|
||||
procedure Test.2 (Test.3):
|
||||
let Test.7 : {} = Struct {};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
procedure List.5 (#Attr.2, #Attr.3):
|
||||
let List.380 : List [] = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.2 #Attr.3;
|
||||
let List.409 : List [] = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.2 #Attr.3;
|
||||
decref #Attr.2;
|
||||
ret List.380;
|
||||
ret List.409;
|
||||
|
||||
procedure Test.2 (Test.3):
|
||||
let Test.7 : {} = Struct {};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.258 : I128 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.258;
|
||||
let Num.257 : I128 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.257;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.6 : I128 = 18446744073709551616i64;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.257 : U128 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.257;
|
||||
let Num.256 : U128 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.256;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.2 : U128 = 170141183460469231731687303715884105728u128;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.257 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.257;
|
||||
let Num.256 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.256;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.2 : U64 = 9999999999999999999i64;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure List.6 (#Attr.2):
|
||||
let List.380 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.380;
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
|
||||
procedure Test.1 (Test.5):
|
||||
let Test.2 : I64 = 41i64;
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
procedure Dict.1 ():
|
||||
let Dict.100 : List {[], []} = Array [];
|
||||
ret Dict.100;
|
||||
let Dict.318 : List {[], []} = Array [];
|
||||
ret Dict.318;
|
||||
|
||||
procedure Dict.7 (Dict.94):
|
||||
let Dict.99 : U64 = CallByName List.6 Dict.94;
|
||||
ret Dict.99;
|
||||
procedure Dict.7 (Dict.312):
|
||||
let Dict.317 : U64 = CallByName List.6 Dict.312;
|
||||
ret Dict.317;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.380 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.380;
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.2 : List {[], []} = CallByName Dict.1;
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
procedure Bool.1 ():
|
||||
let Bool.11 : Int1 = false;
|
||||
ret Bool.11;
|
||||
let Bool.23 : Int1 = false;
|
||||
ret Bool.23;
|
||||
|
||||
procedure List.2 (List.90, List.91):
|
||||
let List.386 : U64 = CallByName List.6 List.90;
|
||||
let List.382 : Int1 = CallByName Num.22 List.91 List.386;
|
||||
if List.382 then
|
||||
let List.384 : {} = CallByName List.66 List.90 List.91;
|
||||
let List.383 : [C {}, C {}] = TagId(1) List.384;
|
||||
ret List.383;
|
||||
procedure List.2 (List.94, List.95):
|
||||
let List.415 : U64 = CallByName List.6 List.94;
|
||||
let List.411 : Int1 = CallByName Num.22 List.95 List.415;
|
||||
if List.411 then
|
||||
let List.413 : {} = CallByName List.66 List.94 List.95;
|
||||
let List.412 : [C {}, C {}] = TagId(1) List.413;
|
||||
ret List.412;
|
||||
else
|
||||
let List.381 : {} = Struct {};
|
||||
let List.380 : [C {}, C {}] = TagId(0) List.381;
|
||||
ret List.380;
|
||||
let List.410 : {} = Struct {};
|
||||
let List.409 : [C {}, C {}] = TagId(0) List.410;
|
||||
ret List.409;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.387 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.387;
|
||||
let List.416 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.416;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.385 : {} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.385;
|
||||
let List.414 : {} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.414;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.257 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.257;
|
||||
let Num.256 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.256;
|
||||
|
||||
procedure Test.2 (Test.5):
|
||||
let Test.17 : Str = "bar";
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
procedure List.4 (List.101, List.102):
|
||||
let List.383 : U64 = 1i64;
|
||||
let List.381 : List U8 = CallByName List.70 List.101 List.383;
|
||||
let List.380 : List U8 = CallByName List.71 List.381 List.102;
|
||||
ret List.380;
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.412 : U64 = 1i64;
|
||||
let List.410 : List U8 = CallByName List.70 List.105 List.412;
|
||||
let List.409 : List U8 = CallByName List.71 List.410 List.106;
|
||||
ret List.409;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.384 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.384;
|
||||
let List.413 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.382 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.382;
|
||||
let List.411 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.411;
|
||||
|
||||
procedure Test.23 (Test.24, Test.35, Test.22):
|
||||
let Test.37 : List U8 = CallByName List.4 Test.24 Test.22;
|
||||
|
|
|
@ -44,7 +44,7 @@ procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
|||
ret Encode.106;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.113 : List U8 = CallByName Json.113 Encode.94 Encode.96 Encode.102;
|
||||
let Encode.113 : List U8 = CallByName Json.112 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.113;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
|
@ -52,11 +52,11 @@ procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
|||
ret Encode.115;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.125 : List U8 = CallByName Json.113 Encode.94 Encode.96 Encode.102;
|
||||
let Encode.125 : List U8 = CallByName Json.112 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.125;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.128 : List U8 = CallByName Json.97 Encode.94 Encode.96 Encode.102;
|
||||
let Encode.128 : List U8 = CallByName Json.96 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.128;
|
||||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
|
@ -66,284 +66,284 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
|
||||
procedure Json.113 (Json.114, Json.399, Json.112):
|
||||
let Json.432 : I32 = 123i64;
|
||||
let Json.431 : U8 = CallByName Num.123 Json.432;
|
||||
let Json.116 : List U8 = CallByName List.4 Json.114 Json.431;
|
||||
let Json.430 : U64 = CallByName List.6 Json.112;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.116, Json.430};
|
||||
let Json.408 : {} = Struct {};
|
||||
let Json.406 : {List U8, U64} = CallByName List.18 Json.112 Json.407 Json.408;
|
||||
dec Json.112;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.406;
|
||||
inc Json.118;
|
||||
dec Json.406;
|
||||
let Json.405 : I32 = 125i64;
|
||||
let Json.404 : U8 = CallByName Num.123 Json.405;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.118 Json.404;
|
||||
ret Json.403;
|
||||
procedure Json.112 (Json.113, Json.397, Json.111):
|
||||
let Json.430 : I64 = 123i64;
|
||||
let Json.429 : U8 = CallByName Num.125 Json.430;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.429;
|
||||
let Json.428 : U64 = CallByName List.6 Json.111;
|
||||
let Json.405 : {List U8, U64} = Struct {Json.115, Json.428};
|
||||
let Json.406 : {} = Struct {};
|
||||
let Json.404 : {List U8, U64} = CallByName List.18 Json.111 Json.405 Json.406;
|
||||
dec Json.111;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.404;
|
||||
inc Json.117;
|
||||
dec Json.404;
|
||||
let Json.403 : I64 = 125i64;
|
||||
let Json.402 : U8 = CallByName Num.125 Json.403;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.117 Json.402;
|
||||
ret Json.401;
|
||||
|
||||
procedure Json.113 (Json.114, Json.399, Json.112):
|
||||
let Json.472 : I32 = 123i64;
|
||||
let Json.471 : U8 = CallByName Num.123 Json.472;
|
||||
let Json.116 : List U8 = CallByName List.4 Json.114 Json.471;
|
||||
let Json.470 : U64 = CallByName List.6 Json.112;
|
||||
let Json.447 : {List U8, U64} = Struct {Json.116, Json.470};
|
||||
let Json.448 : {} = Struct {};
|
||||
let Json.446 : {List U8, U64} = CallByName List.18 Json.112 Json.447 Json.448;
|
||||
dec Json.112;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.446;
|
||||
inc Json.118;
|
||||
dec Json.446;
|
||||
let Json.445 : I32 = 125i64;
|
||||
let Json.444 : U8 = CallByName Num.123 Json.445;
|
||||
let Json.443 : List U8 = CallByName List.4 Json.118 Json.444;
|
||||
ret Json.443;
|
||||
procedure Json.112 (Json.113, Json.397, Json.111):
|
||||
let Json.470 : I64 = 123i64;
|
||||
let Json.469 : U8 = CallByName Num.125 Json.470;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.469;
|
||||
let Json.468 : U64 = CallByName List.6 Json.111;
|
||||
let Json.445 : {List U8, U64} = Struct {Json.115, Json.468};
|
||||
let Json.446 : {} = Struct {};
|
||||
let Json.444 : {List U8, U64} = CallByName List.18 Json.111 Json.445 Json.446;
|
||||
dec Json.111;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.444;
|
||||
inc Json.117;
|
||||
dec Json.444;
|
||||
let Json.443 : I64 = 125i64;
|
||||
let Json.442 : U8 = CallByName Num.125 Json.443;
|
||||
let Json.441 : List U8 = CallByName List.4 Json.117 Json.442;
|
||||
ret Json.441;
|
||||
|
||||
procedure Json.115 (Json.401, Json.402):
|
||||
let Json.121 : Str = StructAtIndex 0 Json.402;
|
||||
procedure Json.114 (Json.399, Json.400):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.400;
|
||||
inc Json.120;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.400;
|
||||
inc Json.121;
|
||||
let Json.122 : Str = StructAtIndex 1 Json.402;
|
||||
inc Json.122;
|
||||
dec Json.402;
|
||||
let Json.119 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.119;
|
||||
let Json.120 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.429 : I32 = 34i64;
|
||||
let Json.428 : U8 = CallByName Num.123 Json.429;
|
||||
let Json.426 : List U8 = CallByName List.4 Json.119 Json.428;
|
||||
let Json.427 : List U8 = CallByName Str.12 Json.121;
|
||||
let Json.423 : List U8 = CallByName List.8 Json.426 Json.427;
|
||||
let Json.425 : I32 = 34i64;
|
||||
let Json.424 : U8 = CallByName Num.123 Json.425;
|
||||
let Json.420 : List U8 = CallByName List.4 Json.423 Json.424;
|
||||
let Json.422 : I32 = 58i64;
|
||||
let Json.421 : U8 = CallByName Num.123 Json.422;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.420 Json.421;
|
||||
let Json.419 : {} = Struct {};
|
||||
let Json.123 : List U8 = CallByName Encode.23 Json.418 Json.122 Json.419;
|
||||
joinpoint Json.413 Json.124:
|
||||
let Json.411 : U64 = 1i64;
|
||||
let Json.410 : U64 = CallByName Num.20 Json.120 Json.411;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.124, Json.410};
|
||||
ret Json.409;
|
||||
dec Json.400;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.399;
|
||||
inc Json.118;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.427 : I64 = 34i64;
|
||||
let Json.426 : U8 = CallByName Num.125 Json.427;
|
||||
let Json.424 : List U8 = CallByName List.4 Json.118 Json.426;
|
||||
let Json.425 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.421 : List U8 = CallByName List.8 Json.424 Json.425;
|
||||
let Json.423 : I64 = 34i64;
|
||||
let Json.422 : U8 = CallByName Num.125 Json.423;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.421 Json.422;
|
||||
let Json.420 : I64 = 58i64;
|
||||
let Json.419 : U8 = CallByName Num.125 Json.420;
|
||||
let Json.416 : List U8 = CallByName List.4 Json.418 Json.419;
|
||||
let Json.417 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.416 Json.121 Json.417;
|
||||
joinpoint Json.411 Json.123:
|
||||
let Json.409 : U64 = 1i64;
|
||||
let Json.408 : U64 = CallByName Num.20 Json.119 Json.409;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.123, Json.408};
|
||||
ret Json.407;
|
||||
in
|
||||
let Json.417 : U64 = 1i64;
|
||||
let Json.414 : Int1 = CallByName Num.24 Json.120 Json.417;
|
||||
if Json.414 then
|
||||
let Json.416 : I32 = 44i64;
|
||||
let Json.415 : U8 = CallByName Num.123 Json.416;
|
||||
let Json.412 : List U8 = CallByName List.4 Json.123 Json.415;
|
||||
jump Json.413 Json.412;
|
||||
let Json.415 : U64 = 1i64;
|
||||
let Json.412 : Int1 = CallByName Num.24 Json.119 Json.415;
|
||||
if Json.412 then
|
||||
let Json.414 : I64 = 44i64;
|
||||
let Json.413 : U8 = CallByName Num.125 Json.414;
|
||||
let Json.410 : List U8 = CallByName List.4 Json.122 Json.413;
|
||||
jump Json.411 Json.410;
|
||||
else
|
||||
jump Json.413 Json.123;
|
||||
jump Json.411 Json.122;
|
||||
|
||||
procedure Json.115 (Json.401, Json.402):
|
||||
let Json.121 : Str = StructAtIndex 0 Json.402;
|
||||
procedure Json.114 (Json.399, Json.400):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.400;
|
||||
inc Json.120;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.400;
|
||||
inc Json.121;
|
||||
let Json.122 : Str = StructAtIndex 1 Json.402;
|
||||
inc Json.122;
|
||||
dec Json.402;
|
||||
let Json.119 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.119;
|
||||
let Json.120 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.469 : I32 = 34i64;
|
||||
let Json.468 : U8 = CallByName Num.123 Json.469;
|
||||
let Json.466 : List U8 = CallByName List.4 Json.119 Json.468;
|
||||
let Json.467 : List U8 = CallByName Str.12 Json.121;
|
||||
let Json.463 : List U8 = CallByName List.8 Json.466 Json.467;
|
||||
let Json.465 : I32 = 34i64;
|
||||
let Json.464 : U8 = CallByName Num.123 Json.465;
|
||||
let Json.460 : List U8 = CallByName List.4 Json.463 Json.464;
|
||||
let Json.462 : I32 = 58i64;
|
||||
let Json.461 : U8 = CallByName Num.123 Json.462;
|
||||
let Json.458 : List U8 = CallByName List.4 Json.460 Json.461;
|
||||
let Json.459 : {} = Struct {};
|
||||
let Json.123 : List U8 = CallByName Encode.23 Json.458 Json.122 Json.459;
|
||||
joinpoint Json.453 Json.124:
|
||||
let Json.451 : U64 = 1i64;
|
||||
let Json.450 : U64 = CallByName Num.20 Json.120 Json.451;
|
||||
let Json.449 : {List U8, U64} = Struct {Json.124, Json.450};
|
||||
ret Json.449;
|
||||
dec Json.400;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.399;
|
||||
inc Json.118;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.467 : I64 = 34i64;
|
||||
let Json.466 : U8 = CallByName Num.125 Json.467;
|
||||
let Json.464 : List U8 = CallByName List.4 Json.118 Json.466;
|
||||
let Json.465 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.461 : List U8 = CallByName List.8 Json.464 Json.465;
|
||||
let Json.463 : I64 = 34i64;
|
||||
let Json.462 : U8 = CallByName Num.125 Json.463;
|
||||
let Json.458 : List U8 = CallByName List.4 Json.461 Json.462;
|
||||
let Json.460 : I64 = 58i64;
|
||||
let Json.459 : U8 = CallByName Num.125 Json.460;
|
||||
let Json.456 : List U8 = CallByName List.4 Json.458 Json.459;
|
||||
let Json.457 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.456 Json.121 Json.457;
|
||||
joinpoint Json.451 Json.123:
|
||||
let Json.449 : U64 = 1i64;
|
||||
let Json.448 : U64 = CallByName Num.20 Json.119 Json.449;
|
||||
let Json.447 : {List U8, U64} = Struct {Json.123, Json.448};
|
||||
ret Json.447;
|
||||
in
|
||||
let Json.457 : U64 = 1i64;
|
||||
let Json.454 : Int1 = CallByName Num.24 Json.120 Json.457;
|
||||
if Json.454 then
|
||||
let Json.456 : I32 = 44i64;
|
||||
let Json.455 : U8 = CallByName Num.123 Json.456;
|
||||
let Json.452 : List U8 = CallByName List.4 Json.123 Json.455;
|
||||
jump Json.453 Json.452;
|
||||
let Json.455 : U64 = 1i64;
|
||||
let Json.452 : Int1 = CallByName Num.24 Json.119 Json.455;
|
||||
if Json.452 then
|
||||
let Json.454 : I64 = 44i64;
|
||||
let Json.453 : U8 = CallByName Num.125 Json.454;
|
||||
let Json.450 : List U8 = CallByName List.4 Json.122 Json.453;
|
||||
jump Json.451 Json.450;
|
||||
else
|
||||
jump Json.453 Json.123;
|
||||
jump Json.451 Json.122;
|
||||
|
||||
procedure Json.18 (Json.96):
|
||||
let Json.473 : Str = CallByName Encode.22 Json.96;
|
||||
ret Json.473;
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.471 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.471;
|
||||
|
||||
procedure Json.20 (Json.112):
|
||||
let Json.397 : List {Str, Str} = CallByName Encode.22 Json.112;
|
||||
ret Json.397;
|
||||
procedure Json.20 (Json.111):
|
||||
let Json.395 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.395;
|
||||
|
||||
procedure Json.20 (Json.112):
|
||||
let Json.439 : List {Str, Str} = CallByName Encode.22 Json.112;
|
||||
ret Json.439;
|
||||
procedure Json.20 (Json.111):
|
||||
let Json.437 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.437;
|
||||
|
||||
procedure Json.97 (Json.98, Json.475, Json.96):
|
||||
let Json.484 : I32 = 34i64;
|
||||
let Json.483 : U8 = CallByName Num.123 Json.484;
|
||||
let Json.481 : List U8 = CallByName List.4 Json.98 Json.483;
|
||||
let Json.482 : List U8 = CallByName Str.12 Json.96;
|
||||
let Json.478 : List U8 = CallByName List.8 Json.481 Json.482;
|
||||
let Json.480 : I32 = 34i64;
|
||||
let Json.479 : U8 = CallByName Num.123 Json.480;
|
||||
let Json.477 : List U8 = CallByName List.4 Json.478 Json.479;
|
||||
ret Json.477;
|
||||
procedure Json.96 (Json.97, Json.473, Json.95):
|
||||
let Json.482 : I64 = 34i64;
|
||||
let Json.481 : U8 = CallByName Num.125 Json.482;
|
||||
let Json.479 : List U8 = CallByName List.4 Json.97 Json.481;
|
||||
let Json.480 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.476 : List U8 = CallByName List.8 Json.479 Json.480;
|
||||
let Json.478 : I64 = 34i64;
|
||||
let Json.477 : U8 = CallByName Num.125 Json.478;
|
||||
let Json.475 : List U8 = CallByName List.4 Json.476 Json.477;
|
||||
ret Json.475;
|
||||
|
||||
procedure List.133 (List.134, List.135, List.132):
|
||||
let List.420 : {List U8, U64} = CallByName Json.115 List.134 List.135;
|
||||
ret List.420;
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.449 : {List U8, U64} = CallByName Json.114 List.138 List.139;
|
||||
ret List.449;
|
||||
|
||||
procedure List.133 (List.134, List.135, List.132):
|
||||
let List.492 : {List U8, U64} = CallByName Json.115 List.134 List.135;
|
||||
ret List.492;
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.521 : {List U8, U64} = CallByName Json.114 List.138 List.139;
|
||||
ret List.521;
|
||||
|
||||
procedure List.18 (List.130, List.131, List.132):
|
||||
let List.402 : {List U8, U64} = CallByName List.75 List.130 List.131 List.132;
|
||||
ret List.402;
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.431 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.431;
|
||||
|
||||
procedure List.18 (List.130, List.131, List.132):
|
||||
let List.474 : {List U8, U64} = CallByName List.75 List.130 List.131 List.132;
|
||||
ret List.474;
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.503 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.503;
|
||||
|
||||
procedure List.4 (List.101, List.102):
|
||||
let List.473 : U64 = 1i64;
|
||||
let List.472 : List U8 = CallByName List.70 List.101 List.473;
|
||||
let List.471 : List U8 = CallByName List.71 List.472 List.102;
|
||||
ret List.471;
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.502 : U64 = 1i64;
|
||||
let List.501 : List U8 = CallByName List.70 List.105 List.502;
|
||||
let List.500 : List U8 = CallByName List.71 List.501 List.106;
|
||||
ret List.500;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.380 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.380;
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.422 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.422;
|
||||
let List.451 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.451;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.495 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.495;
|
||||
let List.524 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.524;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.417 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.417;
|
||||
let List.446 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.446;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.489 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.489;
|
||||
let List.518 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.518;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.452 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.452;
|
||||
let List.481 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.481;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.450 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.450;
|
||||
|
||||
procedure List.75 (List.356, List.357, List.358):
|
||||
let List.406 : U64 = 0i64;
|
||||
let List.407 : U64 = CallByName List.6 List.356;
|
||||
let List.405 : {List U8, U64} = CallByName List.86 List.356 List.357 List.358 List.406 List.407;
|
||||
ret List.405;
|
||||
|
||||
procedure List.75 (List.356, List.357, List.358):
|
||||
let List.478 : U64 = 0i64;
|
||||
let List.479 : U64 = CallByName List.6 List.356;
|
||||
let List.477 : {List U8, U64} = CallByName List.86 List.356 List.357 List.358 List.478 List.479;
|
||||
ret List.477;
|
||||
let List.479 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.479;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.494 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.494;
|
||||
let List.523 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.523;
|
||||
|
||||
procedure List.86 (List.432, List.433, List.434, List.435, List.436):
|
||||
joinpoint List.408 List.359 List.360 List.361 List.362 List.363:
|
||||
let List.410 : Int1 = CallByName Num.22 List.362 List.363;
|
||||
if List.410 then
|
||||
let List.416 : {Str, Str} = CallByName List.66 List.359 List.362;
|
||||
let List.411 : {List U8, U64} = CallByName List.133 List.360 List.416 List.361;
|
||||
let List.414 : U64 = 1i64;
|
||||
let List.413 : U64 = CallByName Num.19 List.362 List.414;
|
||||
jump List.408 List.359 List.411 List.361 List.413 List.363;
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.435 : U64 = 0i64;
|
||||
let List.436 : U64 = CallByName List.6 List.385;
|
||||
let List.434 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.435 List.436;
|
||||
ret List.434;
|
||||
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.507 : U64 = 0i64;
|
||||
let List.508 : U64 = CallByName List.6 List.385;
|
||||
let List.506 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.507 List.508;
|
||||
ret List.506;
|
||||
|
||||
procedure List.90 (List.461, List.462, List.463, List.464, List.465):
|
||||
joinpoint List.437 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.439 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.439 then
|
||||
let List.445 : {Str, Str} = CallByName List.66 List.388 List.391;
|
||||
let List.440 : {List U8, U64} = CallByName List.137 List.389 List.445 List.390;
|
||||
let List.443 : U64 = 1i64;
|
||||
let List.442 : U64 = CallByName Num.19 List.391 List.443;
|
||||
jump List.437 List.388 List.440 List.390 List.442 List.392;
|
||||
else
|
||||
ret List.360;
|
||||
ret List.389;
|
||||
in
|
||||
jump List.408 List.432 List.433 List.434 List.435 List.436;
|
||||
jump List.437 List.461 List.462 List.463 List.464 List.465;
|
||||
|
||||
procedure List.86 (List.505, List.506, List.507, List.508, List.509):
|
||||
joinpoint List.480 List.359 List.360 List.361 List.362 List.363:
|
||||
let List.482 : Int1 = CallByName Num.22 List.362 List.363;
|
||||
if List.482 then
|
||||
let List.488 : {Str, Str} = CallByName List.66 List.359 List.362;
|
||||
let List.483 : {List U8, U64} = CallByName List.133 List.360 List.488 List.361;
|
||||
let List.486 : U64 = 1i64;
|
||||
let List.485 : U64 = CallByName Num.19 List.362 List.486;
|
||||
jump List.480 List.359 List.483 List.361 List.485 List.363;
|
||||
procedure List.90 (List.534, List.535, List.536, List.537, List.538):
|
||||
joinpoint List.509 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.511 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.511 then
|
||||
let List.517 : {Str, Str} = CallByName List.66 List.388 List.391;
|
||||
let List.512 : {List U8, U64} = CallByName List.137 List.389 List.517 List.390;
|
||||
let List.515 : U64 = 1i64;
|
||||
let List.514 : U64 = CallByName Num.19 List.391 List.515;
|
||||
jump List.509 List.388 List.512 List.390 List.514 List.392;
|
||||
else
|
||||
ret List.360;
|
||||
ret List.389;
|
||||
in
|
||||
jump List.480 List.505 List.506 List.507 List.508 List.509;
|
||||
jump List.509 List.534 List.535 List.536 List.537 List.538;
|
||||
|
||||
procedure Num.123 (#Attr.2):
|
||||
let Num.283 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.283;
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.282 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.282;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.286 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.286;
|
||||
|
||||
procedure Num.20 (#Attr.2, #Attr.3):
|
||||
let Num.284 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.284;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.287 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.287;
|
||||
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Num.285 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||
let Num.285 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.285;
|
||||
|
||||
procedure Num.20 (#Attr.2, #Attr.3):
|
||||
let Num.283 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.283;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.286 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.286;
|
||||
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Num.284 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||
ret Num.284;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.268 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.268;
|
||||
let Str.282 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.282;
|
||||
|
||||
procedure Str.48 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let Str.260 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.260;
|
||||
let Str.274 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.274;
|
||||
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.258 : U64 = 0i64;
|
||||
let Str.259 : U64 = CallByName List.6 Str.73;
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.48 Str.73 Str.258 Str.259;
|
||||
let Str.255 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.255 then
|
||||
let Str.257 : Str = StructAtIndex 1 Str.74;
|
||||
inc Str.257;
|
||||
dec Str.74;
|
||||
let Str.256 : [C {U64, U8}, C Str] = TagId(1) Str.257;
|
||||
ret Str.256;
|
||||
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.253 : U8 = StructAtIndex 3 Str.74;
|
||||
let Str.254 : U64 = StructAtIndex 0 Str.74;
|
||||
dec Str.74;
|
||||
let Str.252 : {U64, U8} = Struct {Str.254, Str.253};
|
||||
let Str.251 : [C {U64, U8}, C Str] = TagId(0) Str.252;
|
||||
ret Str.251;
|
||||
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.0 ():
|
||||
let Test.12 : Str = "bar";
|
||||
|
|
|
@ -25,11 +25,11 @@ procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
|||
ret Encode.106;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.113 : List U8 = CallByName Json.113 Encode.94 Encode.96 Encode.102;
|
||||
let Encode.113 : List U8 = CallByName Json.112 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.113;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.116 : List U8 = CallByName Json.97 Encode.94 Encode.96 Encode.102;
|
||||
let Encode.116 : List U8 = CallByName Json.96 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.116;
|
||||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
|
@ -39,188 +39,188 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
|
||||
procedure Json.113 (Json.114, Json.399, Json.112):
|
||||
let Json.432 : I32 = 123i64;
|
||||
let Json.431 : U8 = CallByName Num.123 Json.432;
|
||||
let Json.116 : List U8 = CallByName List.4 Json.114 Json.431;
|
||||
let Json.430 : U64 = CallByName List.6 Json.112;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.116, Json.430};
|
||||
let Json.408 : {} = Struct {};
|
||||
let Json.406 : {List U8, U64} = CallByName List.18 Json.112 Json.407 Json.408;
|
||||
dec Json.112;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.406;
|
||||
inc Json.118;
|
||||
dec Json.406;
|
||||
let Json.405 : I32 = 125i64;
|
||||
let Json.404 : U8 = CallByName Num.123 Json.405;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.118 Json.404;
|
||||
ret Json.403;
|
||||
procedure Json.112 (Json.113, Json.397, Json.111):
|
||||
let Json.430 : I64 = 123i64;
|
||||
let Json.429 : U8 = CallByName Num.125 Json.430;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.429;
|
||||
let Json.428 : U64 = CallByName List.6 Json.111;
|
||||
let Json.405 : {List U8, U64} = Struct {Json.115, Json.428};
|
||||
let Json.406 : {} = Struct {};
|
||||
let Json.404 : {List U8, U64} = CallByName List.18 Json.111 Json.405 Json.406;
|
||||
dec Json.111;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.404;
|
||||
inc Json.117;
|
||||
dec Json.404;
|
||||
let Json.403 : I64 = 125i64;
|
||||
let Json.402 : U8 = CallByName Num.125 Json.403;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.117 Json.402;
|
||||
ret Json.401;
|
||||
|
||||
procedure Json.115 (Json.401, Json.402):
|
||||
let Json.121 : Str = StructAtIndex 0 Json.402;
|
||||
procedure Json.114 (Json.399, Json.400):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.400;
|
||||
inc Json.120;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.400;
|
||||
inc Json.121;
|
||||
let Json.122 : Str = StructAtIndex 1 Json.402;
|
||||
inc Json.122;
|
||||
dec Json.402;
|
||||
let Json.119 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.119;
|
||||
let Json.120 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.429 : I32 = 34i64;
|
||||
let Json.428 : U8 = CallByName Num.123 Json.429;
|
||||
let Json.426 : List U8 = CallByName List.4 Json.119 Json.428;
|
||||
let Json.427 : List U8 = CallByName Str.12 Json.121;
|
||||
let Json.423 : List U8 = CallByName List.8 Json.426 Json.427;
|
||||
let Json.425 : I32 = 34i64;
|
||||
let Json.424 : U8 = CallByName Num.123 Json.425;
|
||||
let Json.420 : List U8 = CallByName List.4 Json.423 Json.424;
|
||||
let Json.422 : I32 = 58i64;
|
||||
let Json.421 : U8 = CallByName Num.123 Json.422;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.420 Json.421;
|
||||
let Json.419 : {} = Struct {};
|
||||
let Json.123 : List U8 = CallByName Encode.23 Json.418 Json.122 Json.419;
|
||||
joinpoint Json.413 Json.124:
|
||||
let Json.411 : U64 = 1i64;
|
||||
let Json.410 : U64 = CallByName Num.20 Json.120 Json.411;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.124, Json.410};
|
||||
ret Json.409;
|
||||
dec Json.400;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.399;
|
||||
inc Json.118;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.427 : I64 = 34i64;
|
||||
let Json.426 : U8 = CallByName Num.125 Json.427;
|
||||
let Json.424 : List U8 = CallByName List.4 Json.118 Json.426;
|
||||
let Json.425 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.421 : List U8 = CallByName List.8 Json.424 Json.425;
|
||||
let Json.423 : I64 = 34i64;
|
||||
let Json.422 : U8 = CallByName Num.125 Json.423;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.421 Json.422;
|
||||
let Json.420 : I64 = 58i64;
|
||||
let Json.419 : U8 = CallByName Num.125 Json.420;
|
||||
let Json.416 : List U8 = CallByName List.4 Json.418 Json.419;
|
||||
let Json.417 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.416 Json.121 Json.417;
|
||||
joinpoint Json.411 Json.123:
|
||||
let Json.409 : U64 = 1i64;
|
||||
let Json.408 : U64 = CallByName Num.20 Json.119 Json.409;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.123, Json.408};
|
||||
ret Json.407;
|
||||
in
|
||||
let Json.417 : U64 = 1i64;
|
||||
let Json.414 : Int1 = CallByName Num.24 Json.120 Json.417;
|
||||
if Json.414 then
|
||||
let Json.416 : I32 = 44i64;
|
||||
let Json.415 : U8 = CallByName Num.123 Json.416;
|
||||
let Json.412 : List U8 = CallByName List.4 Json.123 Json.415;
|
||||
jump Json.413 Json.412;
|
||||
let Json.415 : U64 = 1i64;
|
||||
let Json.412 : Int1 = CallByName Num.24 Json.119 Json.415;
|
||||
if Json.412 then
|
||||
let Json.414 : I64 = 44i64;
|
||||
let Json.413 : U8 = CallByName Num.125 Json.414;
|
||||
let Json.410 : List U8 = CallByName List.4 Json.122 Json.413;
|
||||
jump Json.411 Json.410;
|
||||
else
|
||||
jump Json.413 Json.123;
|
||||
jump Json.411 Json.122;
|
||||
|
||||
procedure Json.18 (Json.96):
|
||||
let Json.433 : Str = CallByName Encode.22 Json.96;
|
||||
ret Json.433;
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.431 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.431;
|
||||
|
||||
procedure Json.20 (Json.112):
|
||||
let Json.397 : List {Str, Str} = CallByName Encode.22 Json.112;
|
||||
ret Json.397;
|
||||
procedure Json.20 (Json.111):
|
||||
let Json.395 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.395;
|
||||
|
||||
procedure Json.97 (Json.98, Json.435, Json.96):
|
||||
let Json.444 : I32 = 34i64;
|
||||
let Json.443 : U8 = CallByName Num.123 Json.444;
|
||||
let Json.441 : List U8 = CallByName List.4 Json.98 Json.443;
|
||||
let Json.442 : List U8 = CallByName Str.12 Json.96;
|
||||
let Json.438 : List U8 = CallByName List.8 Json.441 Json.442;
|
||||
let Json.440 : I32 = 34i64;
|
||||
let Json.439 : U8 = CallByName Num.123 Json.440;
|
||||
let Json.437 : List U8 = CallByName List.4 Json.438 Json.439;
|
||||
ret Json.437;
|
||||
procedure Json.96 (Json.97, Json.433, Json.95):
|
||||
let Json.442 : I64 = 34i64;
|
||||
let Json.441 : U8 = CallByName Num.125 Json.442;
|
||||
let Json.439 : List U8 = CallByName List.4 Json.97 Json.441;
|
||||
let Json.440 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.436 : List U8 = CallByName List.8 Json.439 Json.440;
|
||||
let Json.438 : I64 = 34i64;
|
||||
let Json.437 : U8 = CallByName Num.125 Json.438;
|
||||
let Json.435 : List U8 = CallByName List.4 Json.436 Json.437;
|
||||
ret Json.435;
|
||||
|
||||
procedure List.133 (List.134, List.135, List.132):
|
||||
let List.426 : {List U8, U64} = CallByName Json.115 List.134 List.135;
|
||||
ret List.426;
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.455 : {List U8, U64} = CallByName Json.114 List.138 List.139;
|
||||
ret List.455;
|
||||
|
||||
procedure List.18 (List.130, List.131, List.132):
|
||||
let List.408 : {List U8, U64} = CallByName List.75 List.130 List.131 List.132;
|
||||
ret List.408;
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.437 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.437;
|
||||
|
||||
procedure List.4 (List.101, List.102):
|
||||
let List.407 : U64 = 1i64;
|
||||
let List.406 : List U8 = CallByName List.70 List.101 List.407;
|
||||
let List.405 : List U8 = CallByName List.71 List.406 List.102;
|
||||
ret List.405;
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.436 : U64 = 1i64;
|
||||
let List.435 : List U8 = CallByName List.70 List.105 List.436;
|
||||
let List.434 : List U8 = CallByName List.71 List.435 List.106;
|
||||
ret List.434;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.380 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.380;
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.429 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.429;
|
||||
let List.458 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.458;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.423 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.423;
|
||||
let List.452 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.452;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.386 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.386;
|
||||
let List.415 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.415;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.384 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.384;
|
||||
|
||||
procedure List.75 (List.356, List.357, List.358):
|
||||
let List.412 : U64 = 0i64;
|
||||
let List.413 : U64 = CallByName List.6 List.356;
|
||||
let List.411 : {List U8, U64} = CallByName List.86 List.356 List.357 List.358 List.412 List.413;
|
||||
ret List.411;
|
||||
let List.413 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.428 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.428;
|
||||
let List.457 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.457;
|
||||
|
||||
procedure List.86 (List.439, List.440, List.441, List.442, List.443):
|
||||
joinpoint List.414 List.359 List.360 List.361 List.362 List.363:
|
||||
let List.416 : Int1 = CallByName Num.22 List.362 List.363;
|
||||
if List.416 then
|
||||
let List.422 : {Str, Str} = CallByName List.66 List.359 List.362;
|
||||
let List.417 : {List U8, U64} = CallByName List.133 List.360 List.422 List.361;
|
||||
let List.420 : U64 = 1i64;
|
||||
let List.419 : U64 = CallByName Num.19 List.362 List.420;
|
||||
jump List.414 List.359 List.417 List.361 List.419 List.363;
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.441 : U64 = 0i64;
|
||||
let List.442 : U64 = CallByName List.6 List.385;
|
||||
let List.440 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.441 List.442;
|
||||
ret List.440;
|
||||
|
||||
procedure List.90 (List.468, List.469, List.470, List.471, List.472):
|
||||
joinpoint List.443 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.445 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.445 then
|
||||
let List.451 : {Str, Str} = CallByName List.66 List.388 List.391;
|
||||
let List.446 : {List U8, U64} = CallByName List.137 List.389 List.451 List.390;
|
||||
let List.449 : U64 = 1i64;
|
||||
let List.448 : U64 = CallByName Num.19 List.391 List.449;
|
||||
jump List.443 List.388 List.446 List.390 List.448 List.392;
|
||||
else
|
||||
ret List.360;
|
||||
ret List.389;
|
||||
in
|
||||
jump List.414 List.439 List.440 List.441 List.442 List.443;
|
||||
jump List.443 List.468 List.469 List.470 List.471 List.472;
|
||||
|
||||
procedure Num.123 (#Attr.2):
|
||||
let Num.264 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.264;
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.263 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.263;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.267 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.267;
|
||||
|
||||
procedure Num.20 (#Attr.2, #Attr.3):
|
||||
let Num.265 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.265;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.268 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.268;
|
||||
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Num.266 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||
let Num.266 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.266;
|
||||
|
||||
procedure Num.20 (#Attr.2, #Attr.3):
|
||||
let Num.264 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.264;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.267 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.267;
|
||||
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Num.265 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||
ret Num.265;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.266 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.266;
|
||||
let Str.280 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.280;
|
||||
|
||||
procedure Str.48 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let Str.260 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.260;
|
||||
let Str.274 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.274;
|
||||
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.258 : U64 = 0i64;
|
||||
let Str.259 : U64 = CallByName List.6 Str.73;
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.48 Str.73 Str.258 Str.259;
|
||||
let Str.255 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.255 then
|
||||
let Str.257 : Str = StructAtIndex 1 Str.74;
|
||||
inc Str.257;
|
||||
dec Str.74;
|
||||
let Str.256 : [C {U64, U8}, C Str] = TagId(1) Str.257;
|
||||
ret Str.256;
|
||||
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.253 : U8 = StructAtIndex 3 Str.74;
|
||||
let Str.254 : U64 = StructAtIndex 0 Str.74;
|
||||
dec Str.74;
|
||||
let Str.252 : {U64, U8} = Struct {Str.254, Str.253};
|
||||
let Str.251 : [C {U64, U8}, C Str] = TagId(0) Str.252;
|
||||
ret Str.251;
|
||||
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.0 ():
|
||||
let Test.11 : Str = "foo";
|
||||
|
|
|
@ -33,11 +33,11 @@ procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
|||
ret Encode.106;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.113 : List U8 = CallByName Json.113 Encode.94 Encode.96 Encode.102;
|
||||
let Encode.113 : List U8 = CallByName Json.112 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.113;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.117 : List U8 = CallByName Json.97 Encode.94 Encode.96 Encode.102;
|
||||
let Encode.117 : List U8 = CallByName Json.96 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.117;
|
||||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
|
@ -47,188 +47,188 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
|
||||
procedure Json.113 (Json.114, Json.399, Json.112):
|
||||
let Json.432 : I32 = 123i64;
|
||||
let Json.431 : U8 = CallByName Num.123 Json.432;
|
||||
let Json.116 : List U8 = CallByName List.4 Json.114 Json.431;
|
||||
let Json.430 : U64 = CallByName List.6 Json.112;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.116, Json.430};
|
||||
let Json.408 : {} = Struct {};
|
||||
let Json.406 : {List U8, U64} = CallByName List.18 Json.112 Json.407 Json.408;
|
||||
dec Json.112;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.406;
|
||||
inc Json.118;
|
||||
dec Json.406;
|
||||
let Json.405 : I32 = 125i64;
|
||||
let Json.404 : U8 = CallByName Num.123 Json.405;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.118 Json.404;
|
||||
ret Json.403;
|
||||
procedure Json.112 (Json.113, Json.397, Json.111):
|
||||
let Json.430 : I64 = 123i64;
|
||||
let Json.429 : U8 = CallByName Num.125 Json.430;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.429;
|
||||
let Json.428 : U64 = CallByName List.6 Json.111;
|
||||
let Json.405 : {List U8, U64} = Struct {Json.115, Json.428};
|
||||
let Json.406 : {} = Struct {};
|
||||
let Json.404 : {List U8, U64} = CallByName List.18 Json.111 Json.405 Json.406;
|
||||
dec Json.111;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.404;
|
||||
inc Json.117;
|
||||
dec Json.404;
|
||||
let Json.403 : I64 = 125i64;
|
||||
let Json.402 : U8 = CallByName Num.125 Json.403;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.117 Json.402;
|
||||
ret Json.401;
|
||||
|
||||
procedure Json.115 (Json.401, Json.402):
|
||||
let Json.121 : Str = StructAtIndex 0 Json.402;
|
||||
procedure Json.114 (Json.399, Json.400):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.400;
|
||||
inc Json.120;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.400;
|
||||
inc Json.121;
|
||||
let Json.122 : Str = StructAtIndex 1 Json.402;
|
||||
inc Json.122;
|
||||
dec Json.402;
|
||||
let Json.119 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.119;
|
||||
let Json.120 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.429 : I32 = 34i64;
|
||||
let Json.428 : U8 = CallByName Num.123 Json.429;
|
||||
let Json.426 : List U8 = CallByName List.4 Json.119 Json.428;
|
||||
let Json.427 : List U8 = CallByName Str.12 Json.121;
|
||||
let Json.423 : List U8 = CallByName List.8 Json.426 Json.427;
|
||||
let Json.425 : I32 = 34i64;
|
||||
let Json.424 : U8 = CallByName Num.123 Json.425;
|
||||
let Json.420 : List U8 = CallByName List.4 Json.423 Json.424;
|
||||
let Json.422 : I32 = 58i64;
|
||||
let Json.421 : U8 = CallByName Num.123 Json.422;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.420 Json.421;
|
||||
let Json.419 : {} = Struct {};
|
||||
let Json.123 : List U8 = CallByName Encode.23 Json.418 Json.122 Json.419;
|
||||
joinpoint Json.413 Json.124:
|
||||
let Json.411 : U64 = 1i64;
|
||||
let Json.410 : U64 = CallByName Num.20 Json.120 Json.411;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.124, Json.410};
|
||||
ret Json.409;
|
||||
dec Json.400;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.399;
|
||||
inc Json.118;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.427 : I64 = 34i64;
|
||||
let Json.426 : U8 = CallByName Num.125 Json.427;
|
||||
let Json.424 : List U8 = CallByName List.4 Json.118 Json.426;
|
||||
let Json.425 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.421 : List U8 = CallByName List.8 Json.424 Json.425;
|
||||
let Json.423 : I64 = 34i64;
|
||||
let Json.422 : U8 = CallByName Num.125 Json.423;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.421 Json.422;
|
||||
let Json.420 : I64 = 58i64;
|
||||
let Json.419 : U8 = CallByName Num.125 Json.420;
|
||||
let Json.416 : List U8 = CallByName List.4 Json.418 Json.419;
|
||||
let Json.417 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.416 Json.121 Json.417;
|
||||
joinpoint Json.411 Json.123:
|
||||
let Json.409 : U64 = 1i64;
|
||||
let Json.408 : U64 = CallByName Num.20 Json.119 Json.409;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.123, Json.408};
|
||||
ret Json.407;
|
||||
in
|
||||
let Json.417 : U64 = 1i64;
|
||||
let Json.414 : Int1 = CallByName Num.24 Json.120 Json.417;
|
||||
if Json.414 then
|
||||
let Json.416 : I32 = 44i64;
|
||||
let Json.415 : U8 = CallByName Num.123 Json.416;
|
||||
let Json.412 : List U8 = CallByName List.4 Json.123 Json.415;
|
||||
jump Json.413 Json.412;
|
||||
let Json.415 : U64 = 1i64;
|
||||
let Json.412 : Int1 = CallByName Num.24 Json.119 Json.415;
|
||||
if Json.412 then
|
||||
let Json.414 : I64 = 44i64;
|
||||
let Json.413 : U8 = CallByName Num.125 Json.414;
|
||||
let Json.410 : List U8 = CallByName List.4 Json.122 Json.413;
|
||||
jump Json.411 Json.410;
|
||||
else
|
||||
jump Json.413 Json.123;
|
||||
jump Json.411 Json.122;
|
||||
|
||||
procedure Json.18 (Json.96):
|
||||
let Json.445 : Str = CallByName Encode.22 Json.96;
|
||||
ret Json.445;
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.443 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.443;
|
||||
|
||||
procedure Json.20 (Json.112):
|
||||
let Json.397 : List {Str, Str} = CallByName Encode.22 Json.112;
|
||||
ret Json.397;
|
||||
procedure Json.20 (Json.111):
|
||||
let Json.395 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.395;
|
||||
|
||||
procedure Json.97 (Json.98, Json.435, Json.96):
|
||||
let Json.444 : I32 = 34i64;
|
||||
let Json.443 : U8 = CallByName Num.123 Json.444;
|
||||
let Json.441 : List U8 = CallByName List.4 Json.98 Json.443;
|
||||
let Json.442 : List U8 = CallByName Str.12 Json.96;
|
||||
let Json.438 : List U8 = CallByName List.8 Json.441 Json.442;
|
||||
let Json.440 : I32 = 34i64;
|
||||
let Json.439 : U8 = CallByName Num.123 Json.440;
|
||||
let Json.437 : List U8 = CallByName List.4 Json.438 Json.439;
|
||||
ret Json.437;
|
||||
procedure Json.96 (Json.97, Json.433, Json.95):
|
||||
let Json.442 : I64 = 34i64;
|
||||
let Json.441 : U8 = CallByName Num.125 Json.442;
|
||||
let Json.439 : List U8 = CallByName List.4 Json.97 Json.441;
|
||||
let Json.440 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.436 : List U8 = CallByName List.8 Json.439 Json.440;
|
||||
let Json.438 : I64 = 34i64;
|
||||
let Json.437 : U8 = CallByName Num.125 Json.438;
|
||||
let Json.435 : List U8 = CallByName List.4 Json.436 Json.437;
|
||||
ret Json.435;
|
||||
|
||||
procedure List.133 (List.134, List.135, List.132):
|
||||
let List.426 : {List U8, U64} = CallByName Json.115 List.134 List.135;
|
||||
ret List.426;
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.455 : {List U8, U64} = CallByName Json.114 List.138 List.139;
|
||||
ret List.455;
|
||||
|
||||
procedure List.18 (List.130, List.131, List.132):
|
||||
let List.408 : {List U8, U64} = CallByName List.75 List.130 List.131 List.132;
|
||||
ret List.408;
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.437 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.437;
|
||||
|
||||
procedure List.4 (List.101, List.102):
|
||||
let List.407 : U64 = 1i64;
|
||||
let List.406 : List U8 = CallByName List.70 List.101 List.407;
|
||||
let List.405 : List U8 = CallByName List.71 List.406 List.102;
|
||||
ret List.405;
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.436 : U64 = 1i64;
|
||||
let List.435 : List U8 = CallByName List.70 List.105 List.436;
|
||||
let List.434 : List U8 = CallByName List.71 List.435 List.106;
|
||||
ret List.434;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.380 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.380;
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.429 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.429;
|
||||
let List.458 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.458;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.423 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.423;
|
||||
let List.452 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.452;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.386 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.386;
|
||||
let List.415 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.415;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.384 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.384;
|
||||
|
||||
procedure List.75 (List.356, List.357, List.358):
|
||||
let List.412 : U64 = 0i64;
|
||||
let List.413 : U64 = CallByName List.6 List.356;
|
||||
let List.411 : {List U8, U64} = CallByName List.86 List.356 List.357 List.358 List.412 List.413;
|
||||
ret List.411;
|
||||
let List.413 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.428 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.428;
|
||||
let List.457 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.457;
|
||||
|
||||
procedure List.86 (List.439, List.440, List.441, List.442, List.443):
|
||||
joinpoint List.414 List.359 List.360 List.361 List.362 List.363:
|
||||
let List.416 : Int1 = CallByName Num.22 List.362 List.363;
|
||||
if List.416 then
|
||||
let List.422 : {Str, Str} = CallByName List.66 List.359 List.362;
|
||||
let List.417 : {List U8, U64} = CallByName List.133 List.360 List.422 List.361;
|
||||
let List.420 : U64 = 1i64;
|
||||
let List.419 : U64 = CallByName Num.19 List.362 List.420;
|
||||
jump List.414 List.359 List.417 List.361 List.419 List.363;
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.441 : U64 = 0i64;
|
||||
let List.442 : U64 = CallByName List.6 List.385;
|
||||
let List.440 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.441 List.442;
|
||||
ret List.440;
|
||||
|
||||
procedure List.90 (List.468, List.469, List.470, List.471, List.472):
|
||||
joinpoint List.443 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.445 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.445 then
|
||||
let List.451 : {Str, Str} = CallByName List.66 List.388 List.391;
|
||||
let List.446 : {List U8, U64} = CallByName List.137 List.389 List.451 List.390;
|
||||
let List.449 : U64 = 1i64;
|
||||
let List.448 : U64 = CallByName Num.19 List.391 List.449;
|
||||
jump List.443 List.388 List.446 List.390 List.448 List.392;
|
||||
else
|
||||
ret List.360;
|
||||
ret List.389;
|
||||
in
|
||||
jump List.414 List.439 List.440 List.441 List.442 List.443;
|
||||
jump List.443 List.468 List.469 List.470 List.471 List.472;
|
||||
|
||||
procedure Num.123 (#Attr.2):
|
||||
let Num.264 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.264;
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.263 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.263;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.267 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.267;
|
||||
|
||||
procedure Num.20 (#Attr.2, #Attr.3):
|
||||
let Num.265 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.265;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.268 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.268;
|
||||
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Num.266 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||
let Num.266 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.266;
|
||||
|
||||
procedure Num.20 (#Attr.2, #Attr.3):
|
||||
let Num.264 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.264;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.267 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.267;
|
||||
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Num.265 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||
ret Num.265;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.266 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.266;
|
||||
let Str.280 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.280;
|
||||
|
||||
procedure Str.48 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let Str.260 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.260;
|
||||
let Str.274 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.274;
|
||||
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.258 : U64 = 0i64;
|
||||
let Str.259 : U64 = CallByName List.6 Str.73;
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.48 Str.73 Str.258 Str.259;
|
||||
let Str.255 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.255 then
|
||||
let Str.257 : Str = StructAtIndex 1 Str.74;
|
||||
inc Str.257;
|
||||
dec Str.74;
|
||||
let Str.256 : [C {U64, U8}, C Str] = TagId(1) Str.257;
|
||||
ret Str.256;
|
||||
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.253 : U8 = StructAtIndex 3 Str.74;
|
||||
let Str.254 : U64 = StructAtIndex 0 Str.74;
|
||||
dec Str.74;
|
||||
let Str.252 : {U64, U8} = Struct {Str.254, Str.253};
|
||||
let Str.251 : [C {U64, U8}, C Str] = TagId(0) Str.252;
|
||||
ret Str.251;
|
||||
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.0 ():
|
||||
let Test.11 : Str = "foo";
|
||||
|
|
|
@ -2,7 +2,7 @@ procedure Encode.22 (Encode.93):
|
|||
ret Encode.93;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.106 : List U8 = CallByName Json.97 Encode.94 Encode.96 Encode.102;
|
||||
let Encode.106 : List U8 = CallByName Json.96 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.106;
|
||||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
|
@ -12,76 +12,76 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
|
||||
procedure Json.18 (Json.96):
|
||||
let Json.397 : Str = CallByName Encode.22 Json.96;
|
||||
ret Json.397;
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.395 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.395;
|
||||
|
||||
procedure Json.97 (Json.98, Json.399, Json.96):
|
||||
let Json.408 : I32 = 34i64;
|
||||
let Json.407 : U8 = CallByName Num.123 Json.408;
|
||||
let Json.405 : List U8 = CallByName List.4 Json.98 Json.407;
|
||||
let Json.406 : List U8 = CallByName Str.12 Json.96;
|
||||
let Json.402 : List U8 = CallByName List.8 Json.405 Json.406;
|
||||
let Json.404 : I32 = 34i64;
|
||||
let Json.403 : U8 = CallByName Num.123 Json.404;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.402 Json.403;
|
||||
ret Json.401;
|
||||
procedure Json.96 (Json.97, Json.397, Json.95):
|
||||
let Json.406 : I64 = 34i64;
|
||||
let Json.405 : U8 = CallByName Num.125 Json.406;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.97 Json.405;
|
||||
let Json.404 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.400 : List U8 = CallByName List.8 Json.403 Json.404;
|
||||
let Json.402 : I64 = 34i64;
|
||||
let Json.401 : U8 = CallByName Num.125 Json.402;
|
||||
let Json.399 : List U8 = CallByName List.4 Json.400 Json.401;
|
||||
ret Json.399;
|
||||
|
||||
procedure List.4 (List.101, List.102):
|
||||
let List.389 : U64 = 1i64;
|
||||
let List.388 : List U8 = CallByName List.70 List.101 List.389;
|
||||
let List.387 : List U8 = CallByName List.71 List.388 List.102;
|
||||
ret List.387;
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.418 : U64 = 1i64;
|
||||
let List.417 : List U8 = CallByName List.70 List.105 List.418;
|
||||
let List.416 : List U8 = CallByName List.71 List.417 List.106;
|
||||
ret List.416;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.380 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.380;
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.386 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.386;
|
||||
let List.415 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.415;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.384 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.384;
|
||||
let List.413 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.390 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.390;
|
||||
let List.419 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.419;
|
||||
|
||||
procedure Num.123 (#Attr.2):
|
||||
let Num.258 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.258;
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.257 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.257;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.265 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.265;
|
||||
let Str.279 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.279;
|
||||
|
||||
procedure Str.48 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let Str.260 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.260;
|
||||
let Str.274 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.274;
|
||||
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.258 : U64 = 0i64;
|
||||
let Str.259 : U64 = CallByName List.6 Str.73;
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.48 Str.73 Str.258 Str.259;
|
||||
let Str.255 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.255 then
|
||||
let Str.257 : Str = StructAtIndex 1 Str.74;
|
||||
inc Str.257;
|
||||
dec Str.74;
|
||||
let Str.256 : [C {U64, U8}, C Str] = TagId(1) Str.257;
|
||||
ret Str.256;
|
||||
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.253 : U8 = StructAtIndex 3 Str.74;
|
||||
let Str.254 : U64 = StructAtIndex 0 Str.74;
|
||||
dec Str.74;
|
||||
let Str.252 : {U64, U8} = Struct {Str.254, Str.253};
|
||||
let Str.251 : [C {U64, U8}, C Str] = TagId(0) Str.252;
|
||||
ret Str.251;
|
||||
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.0 ():
|
||||
let Test.9 : Str = "abc";
|
||||
|
|
|
@ -27,11 +27,11 @@ procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
|||
ret Encode.106;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.113 : List U8 = CallByName Json.127 Encode.94 Encode.96 Encode.102;
|
||||
let Encode.113 : List U8 = CallByName Json.126 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.113;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.116 : List U8 = CallByName Json.97 Encode.94 Encode.96 Encode.102;
|
||||
let Encode.116 : List U8 = CallByName Json.96 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.116;
|
||||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
|
@ -41,195 +41,195 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
|
||||
procedure Json.127 (Json.128, Json.399, #Attr.12):
|
||||
let Json.126 : List Str = StructAtIndex 1 #Attr.12;
|
||||
inc Json.126;
|
||||
let Json.125 : Str = StructAtIndex 0 #Attr.12;
|
||||
procedure Json.126 (Json.127, Json.397, #Attr.12):
|
||||
let Json.125 : List Str = StructAtIndex 1 #Attr.12;
|
||||
inc Json.125;
|
||||
let Json.124 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.124;
|
||||
dec #Attr.12;
|
||||
let Json.437 : I32 = 123i64;
|
||||
let Json.436 : U8 = CallByName Num.123 Json.437;
|
||||
let Json.433 : List U8 = CallByName List.4 Json.128 Json.436;
|
||||
let Json.435 : I32 = 34i64;
|
||||
let Json.434 : U8 = CallByName Num.123 Json.435;
|
||||
let Json.431 : List U8 = CallByName List.4 Json.433 Json.434;
|
||||
let Json.432 : List U8 = CallByName Str.12 Json.125;
|
||||
let Json.428 : List U8 = CallByName List.8 Json.431 Json.432;
|
||||
let Json.430 : I32 = 34i64;
|
||||
let Json.429 : U8 = CallByName Num.123 Json.430;
|
||||
let Json.425 : List U8 = CallByName List.4 Json.428 Json.429;
|
||||
let Json.427 : I32 = 58i64;
|
||||
let Json.426 : U8 = CallByName Num.123 Json.427;
|
||||
let Json.422 : List U8 = CallByName List.4 Json.425 Json.426;
|
||||
let Json.424 : I32 = 91i64;
|
||||
let Json.423 : U8 = CallByName Num.123 Json.424;
|
||||
let Json.130 : List U8 = CallByName List.4 Json.422 Json.423;
|
||||
let Json.421 : U64 = CallByName List.6 Json.126;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.130, Json.421};
|
||||
let Json.410 : {} = Struct {};
|
||||
let Json.408 : {List U8, U64} = CallByName List.18 Json.126 Json.409 Json.410;
|
||||
dec Json.126;
|
||||
let Json.132 : List U8 = StructAtIndex 0 Json.408;
|
||||
let Json.435 : I64 = 123i64;
|
||||
let Json.434 : U8 = CallByName Num.125 Json.435;
|
||||
let Json.431 : List U8 = CallByName List.4 Json.127 Json.434;
|
||||
let Json.433 : I64 = 34i64;
|
||||
let Json.432 : U8 = CallByName Num.125 Json.433;
|
||||
let Json.429 : List U8 = CallByName List.4 Json.431 Json.432;
|
||||
let Json.430 : List U8 = CallByName Str.12 Json.124;
|
||||
let Json.426 : List U8 = CallByName List.8 Json.429 Json.430;
|
||||
let Json.428 : I64 = 34i64;
|
||||
let Json.427 : U8 = CallByName Num.125 Json.428;
|
||||
let Json.423 : List U8 = CallByName List.4 Json.426 Json.427;
|
||||
let Json.425 : I64 = 58i64;
|
||||
let Json.424 : U8 = CallByName Num.125 Json.425;
|
||||
let Json.420 : List U8 = CallByName List.4 Json.423 Json.424;
|
||||
let Json.422 : I64 = 91i64;
|
||||
let Json.421 : U8 = CallByName Num.125 Json.422;
|
||||
let Json.129 : List U8 = CallByName List.4 Json.420 Json.421;
|
||||
let Json.419 : U64 = CallByName List.6 Json.125;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.129, Json.419};
|
||||
let Json.408 : {} = Struct {};
|
||||
let Json.406 : {List U8, U64} = CallByName List.18 Json.125 Json.407 Json.408;
|
||||
dec Json.125;
|
||||
let Json.131 : List U8 = StructAtIndex 0 Json.406;
|
||||
inc Json.131;
|
||||
dec Json.406;
|
||||
let Json.405 : I64 = 93i64;
|
||||
let Json.404 : U8 = CallByName Num.125 Json.405;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.131 Json.404;
|
||||
let Json.403 : I64 = 125i64;
|
||||
let Json.402 : U8 = CallByName Num.125 Json.403;
|
||||
let Json.400 : List U8 = CallByName List.4 Json.401 Json.402;
|
||||
ret Json.400;
|
||||
|
||||
procedure Json.128 (Json.399, Json.134):
|
||||
let Json.132 : List U8 = StructAtIndex 0 Json.399;
|
||||
inc Json.132;
|
||||
dec Json.408;
|
||||
let Json.407 : I32 = 93i64;
|
||||
let Json.406 : U8 = CallByName Num.123 Json.407;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.132 Json.406;
|
||||
let Json.405 : I32 = 125i64;
|
||||
let Json.404 : U8 = CallByName Num.123 Json.405;
|
||||
let Json.402 : List U8 = CallByName List.4 Json.403 Json.404;
|
||||
ret Json.402;
|
||||
|
||||
procedure Json.129 (Json.401, Json.135):
|
||||
let Json.133 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.133;
|
||||
let Json.134 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.420 : {} = Struct {};
|
||||
let Json.136 : List U8 = CallByName Encode.23 Json.133 Json.135 Json.420;
|
||||
joinpoint Json.415 Json.137:
|
||||
let Json.413 : U64 = 1i64;
|
||||
let Json.412 : U64 = CallByName Num.20 Json.134 Json.413;
|
||||
let Json.411 : {List U8, U64} = Struct {Json.137, Json.412};
|
||||
ret Json.411;
|
||||
let Json.133 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.418 : {} = Struct {};
|
||||
let Json.135 : List U8 = CallByName Encode.23 Json.132 Json.134 Json.418;
|
||||
joinpoint Json.413 Json.136:
|
||||
let Json.411 : U64 = 1i64;
|
||||
let Json.410 : U64 = CallByName Num.20 Json.133 Json.411;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.136, Json.410};
|
||||
ret Json.409;
|
||||
in
|
||||
let Json.419 : U64 = 1i64;
|
||||
let Json.416 : Int1 = CallByName Num.24 Json.134 Json.419;
|
||||
if Json.416 then
|
||||
let Json.418 : I32 = 44i64;
|
||||
let Json.417 : U8 = CallByName Num.123 Json.418;
|
||||
let Json.414 : List U8 = CallByName List.4 Json.136 Json.417;
|
||||
jump Json.415 Json.414;
|
||||
let Json.417 : U64 = 1i64;
|
||||
let Json.414 : Int1 = CallByName Num.24 Json.133 Json.417;
|
||||
if Json.414 then
|
||||
let Json.416 : I64 = 44i64;
|
||||
let Json.415 : U8 = CallByName Num.125 Json.416;
|
||||
let Json.412 : List U8 = CallByName List.4 Json.135 Json.415;
|
||||
jump Json.413 Json.412;
|
||||
else
|
||||
jump Json.415 Json.136;
|
||||
jump Json.413 Json.135;
|
||||
|
||||
procedure Json.18 (Json.96):
|
||||
let Json.438 : Str = CallByName Encode.22 Json.96;
|
||||
ret Json.438;
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.436 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.436;
|
||||
|
||||
procedure Json.21 (Json.125, Json.126):
|
||||
let Json.398 : {Str, List Str} = Struct {Json.125, Json.126};
|
||||
let Json.397 : {Str, List Str} = CallByName Encode.22 Json.398;
|
||||
ret Json.397;
|
||||
procedure Json.21 (Json.124, Json.125):
|
||||
let Json.396 : {Str, List Str} = Struct {Json.124, Json.125};
|
||||
let Json.395 : {Str, List Str} = CallByName Encode.22 Json.396;
|
||||
ret Json.395;
|
||||
|
||||
procedure Json.97 (Json.98, Json.440, Json.96):
|
||||
let Json.449 : I32 = 34i64;
|
||||
let Json.448 : U8 = CallByName Num.123 Json.449;
|
||||
let Json.446 : List U8 = CallByName List.4 Json.98 Json.448;
|
||||
let Json.447 : List U8 = CallByName Str.12 Json.96;
|
||||
let Json.443 : List U8 = CallByName List.8 Json.446 Json.447;
|
||||
let Json.445 : I32 = 34i64;
|
||||
let Json.444 : U8 = CallByName Num.123 Json.445;
|
||||
let Json.442 : List U8 = CallByName List.4 Json.443 Json.444;
|
||||
ret Json.442;
|
||||
procedure Json.96 (Json.97, Json.438, Json.95):
|
||||
let Json.447 : I64 = 34i64;
|
||||
let Json.446 : U8 = CallByName Num.125 Json.447;
|
||||
let Json.444 : List U8 = CallByName List.4 Json.97 Json.446;
|
||||
let Json.445 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.441 : List U8 = CallByName List.8 Json.444 Json.445;
|
||||
let Json.443 : I64 = 34i64;
|
||||
let Json.442 : U8 = CallByName Num.125 Json.443;
|
||||
let Json.440 : List U8 = CallByName List.4 Json.441 Json.442;
|
||||
ret Json.440;
|
||||
|
||||
procedure List.133 (List.134, List.135, List.132):
|
||||
let List.432 : {List U8, U64} = CallByName Json.129 List.134 List.135;
|
||||
ret List.432;
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.461 : {List U8, U64} = CallByName Json.128 List.138 List.139;
|
||||
ret List.461;
|
||||
|
||||
procedure List.18 (List.130, List.131, List.132):
|
||||
let List.414 : {List U8, U64} = CallByName List.75 List.130 List.131 List.132;
|
||||
ret List.414;
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.443 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.443;
|
||||
|
||||
procedure List.4 (List.101, List.102):
|
||||
let List.413 : U64 = 1i64;
|
||||
let List.412 : List U8 = CallByName List.70 List.101 List.413;
|
||||
let List.411 : List U8 = CallByName List.71 List.412 List.102;
|
||||
ret List.411;
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.442 : U64 = 1i64;
|
||||
let List.441 : List U8 = CallByName List.70 List.105 List.442;
|
||||
let List.440 : List U8 = CallByName List.71 List.441 List.106;
|
||||
ret List.440;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.380 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.380;
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.433 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.433;
|
||||
let List.462 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.462;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.429 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.429;
|
||||
let List.458 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.458;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.386 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.386;
|
||||
let List.415 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.415;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.384 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.384;
|
||||
|
||||
procedure List.75 (List.356, List.357, List.358):
|
||||
let List.418 : U64 = 0i64;
|
||||
let List.419 : U64 = CallByName List.6 List.356;
|
||||
let List.417 : {List U8, U64} = CallByName List.86 List.356 List.357 List.358 List.418 List.419;
|
||||
ret List.417;
|
||||
let List.413 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.435 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.435;
|
||||
let List.464 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.464;
|
||||
|
||||
procedure List.86 (List.445, List.446, List.447, List.448, List.449):
|
||||
joinpoint List.420 List.359 List.360 List.361 List.362 List.363:
|
||||
let List.422 : Int1 = CallByName Num.22 List.362 List.363;
|
||||
if List.422 then
|
||||
let List.428 : Str = CallByName List.66 List.359 List.362;
|
||||
let List.423 : {List U8, U64} = CallByName List.133 List.360 List.428 List.361;
|
||||
let List.426 : U64 = 1i64;
|
||||
let List.425 : U64 = CallByName Num.19 List.362 List.426;
|
||||
jump List.420 List.359 List.423 List.361 List.425 List.363;
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.447 : U64 = 0i64;
|
||||
let List.448 : U64 = CallByName List.6 List.385;
|
||||
let List.446 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.447 List.448;
|
||||
ret List.446;
|
||||
|
||||
procedure List.90 (List.474, List.475, List.476, List.477, List.478):
|
||||
joinpoint List.449 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.451 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.451 then
|
||||
let List.457 : Str = CallByName List.66 List.388 List.391;
|
||||
let List.452 : {List U8, U64} = CallByName List.137 List.389 List.457 List.390;
|
||||
let List.455 : U64 = 1i64;
|
||||
let List.454 : U64 = CallByName Num.19 List.391 List.455;
|
||||
jump List.449 List.388 List.452 List.390 List.454 List.392;
|
||||
else
|
||||
ret List.360;
|
||||
ret List.389;
|
||||
in
|
||||
jump List.420 List.445 List.446 List.447 List.448 List.449;
|
||||
jump List.449 List.474 List.475 List.476 List.477 List.478;
|
||||
|
||||
procedure Num.123 (#Attr.2):
|
||||
let Num.266 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.266;
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.265 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.265;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.269 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.269;
|
||||
|
||||
procedure Num.20 (#Attr.2, #Attr.3):
|
||||
let Num.267 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.267;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.270 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.270;
|
||||
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Num.268 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||
let Num.268 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.268;
|
||||
|
||||
procedure Num.20 (#Attr.2, #Attr.3):
|
||||
let Num.266 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.266;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.269 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.269;
|
||||
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Num.267 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||
ret Num.267;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.266 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.266;
|
||||
let Str.280 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.280;
|
||||
|
||||
procedure Str.48 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let Str.260 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.260;
|
||||
let Str.274 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.274;
|
||||
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.258 : U64 = 0i64;
|
||||
let Str.259 : U64 = CallByName List.6 Str.73;
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.48 Str.73 Str.258 Str.259;
|
||||
let Str.255 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.255 then
|
||||
let Str.257 : Str = StructAtIndex 1 Str.74;
|
||||
inc Str.257;
|
||||
dec Str.74;
|
||||
let Str.256 : [C {U64, U8}, C Str] = TagId(1) Str.257;
|
||||
ret Str.256;
|
||||
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.253 : U8 = StructAtIndex 3 Str.74;
|
||||
let Str.254 : U64 = StructAtIndex 0 Str.74;
|
||||
dec Str.74;
|
||||
let Str.252 : {U64, U8} = Struct {Str.254, Str.253};
|
||||
let Str.251 : [C {U64, U8}, C Str] = TagId(0) Str.252;
|
||||
ret Str.251;
|
||||
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.0 ():
|
||||
let Test.12 : Str = "foo";
|
||||
|
|
|
@ -33,11 +33,11 @@ procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
|||
ret Encode.106;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.113 : List U8 = CallByName Json.127 Encode.94 Encode.96 Encode.102;
|
||||
let Encode.113 : List U8 = CallByName Json.126 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.113;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.117 : List U8 = CallByName Json.97 Encode.94 Encode.96 Encode.102;
|
||||
let Encode.117 : List U8 = CallByName Json.96 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.117;
|
||||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
|
@ -47,195 +47,195 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
|
||||
procedure Json.127 (Json.128, Json.399, #Attr.12):
|
||||
let Json.126 : List Str = StructAtIndex 1 #Attr.12;
|
||||
inc Json.126;
|
||||
let Json.125 : Str = StructAtIndex 0 #Attr.12;
|
||||
procedure Json.126 (Json.127, Json.397, #Attr.12):
|
||||
let Json.125 : List Str = StructAtIndex 1 #Attr.12;
|
||||
inc Json.125;
|
||||
let Json.124 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.124;
|
||||
dec #Attr.12;
|
||||
let Json.437 : I32 = 123i64;
|
||||
let Json.436 : U8 = CallByName Num.123 Json.437;
|
||||
let Json.433 : List U8 = CallByName List.4 Json.128 Json.436;
|
||||
let Json.435 : I32 = 34i64;
|
||||
let Json.434 : U8 = CallByName Num.123 Json.435;
|
||||
let Json.431 : List U8 = CallByName List.4 Json.433 Json.434;
|
||||
let Json.432 : List U8 = CallByName Str.12 Json.125;
|
||||
let Json.428 : List U8 = CallByName List.8 Json.431 Json.432;
|
||||
let Json.430 : I32 = 34i64;
|
||||
let Json.429 : U8 = CallByName Num.123 Json.430;
|
||||
let Json.425 : List U8 = CallByName List.4 Json.428 Json.429;
|
||||
let Json.427 : I32 = 58i64;
|
||||
let Json.426 : U8 = CallByName Num.123 Json.427;
|
||||
let Json.422 : List U8 = CallByName List.4 Json.425 Json.426;
|
||||
let Json.424 : I32 = 91i64;
|
||||
let Json.423 : U8 = CallByName Num.123 Json.424;
|
||||
let Json.130 : List U8 = CallByName List.4 Json.422 Json.423;
|
||||
let Json.421 : U64 = CallByName List.6 Json.126;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.130, Json.421};
|
||||
let Json.410 : {} = Struct {};
|
||||
let Json.408 : {List U8, U64} = CallByName List.18 Json.126 Json.409 Json.410;
|
||||
dec Json.126;
|
||||
let Json.132 : List U8 = StructAtIndex 0 Json.408;
|
||||
let Json.435 : I64 = 123i64;
|
||||
let Json.434 : U8 = CallByName Num.125 Json.435;
|
||||
let Json.431 : List U8 = CallByName List.4 Json.127 Json.434;
|
||||
let Json.433 : I64 = 34i64;
|
||||
let Json.432 : U8 = CallByName Num.125 Json.433;
|
||||
let Json.429 : List U8 = CallByName List.4 Json.431 Json.432;
|
||||
let Json.430 : List U8 = CallByName Str.12 Json.124;
|
||||
let Json.426 : List U8 = CallByName List.8 Json.429 Json.430;
|
||||
let Json.428 : I64 = 34i64;
|
||||
let Json.427 : U8 = CallByName Num.125 Json.428;
|
||||
let Json.423 : List U8 = CallByName List.4 Json.426 Json.427;
|
||||
let Json.425 : I64 = 58i64;
|
||||
let Json.424 : U8 = CallByName Num.125 Json.425;
|
||||
let Json.420 : List U8 = CallByName List.4 Json.423 Json.424;
|
||||
let Json.422 : I64 = 91i64;
|
||||
let Json.421 : U8 = CallByName Num.125 Json.422;
|
||||
let Json.129 : List U8 = CallByName List.4 Json.420 Json.421;
|
||||
let Json.419 : U64 = CallByName List.6 Json.125;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.129, Json.419};
|
||||
let Json.408 : {} = Struct {};
|
||||
let Json.406 : {List U8, U64} = CallByName List.18 Json.125 Json.407 Json.408;
|
||||
dec Json.125;
|
||||
let Json.131 : List U8 = StructAtIndex 0 Json.406;
|
||||
inc Json.131;
|
||||
dec Json.406;
|
||||
let Json.405 : I64 = 93i64;
|
||||
let Json.404 : U8 = CallByName Num.125 Json.405;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.131 Json.404;
|
||||
let Json.403 : I64 = 125i64;
|
||||
let Json.402 : U8 = CallByName Num.125 Json.403;
|
||||
let Json.400 : List U8 = CallByName List.4 Json.401 Json.402;
|
||||
ret Json.400;
|
||||
|
||||
procedure Json.128 (Json.399, Json.134):
|
||||
let Json.132 : List U8 = StructAtIndex 0 Json.399;
|
||||
inc Json.132;
|
||||
dec Json.408;
|
||||
let Json.407 : I32 = 93i64;
|
||||
let Json.406 : U8 = CallByName Num.123 Json.407;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.132 Json.406;
|
||||
let Json.405 : I32 = 125i64;
|
||||
let Json.404 : U8 = CallByName Num.123 Json.405;
|
||||
let Json.402 : List U8 = CallByName List.4 Json.403 Json.404;
|
||||
ret Json.402;
|
||||
|
||||
procedure Json.129 (Json.401, Json.135):
|
||||
let Json.133 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.133;
|
||||
let Json.134 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.420 : {} = Struct {};
|
||||
let Json.136 : List U8 = CallByName Encode.23 Json.133 Json.135 Json.420;
|
||||
joinpoint Json.415 Json.137:
|
||||
let Json.413 : U64 = 1i64;
|
||||
let Json.412 : U64 = CallByName Num.20 Json.134 Json.413;
|
||||
let Json.411 : {List U8, U64} = Struct {Json.137, Json.412};
|
||||
ret Json.411;
|
||||
let Json.133 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.418 : {} = Struct {};
|
||||
let Json.135 : List U8 = CallByName Encode.23 Json.132 Json.134 Json.418;
|
||||
joinpoint Json.413 Json.136:
|
||||
let Json.411 : U64 = 1i64;
|
||||
let Json.410 : U64 = CallByName Num.20 Json.133 Json.411;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.136, Json.410};
|
||||
ret Json.409;
|
||||
in
|
||||
let Json.419 : U64 = 1i64;
|
||||
let Json.416 : Int1 = CallByName Num.24 Json.134 Json.419;
|
||||
if Json.416 then
|
||||
let Json.418 : I32 = 44i64;
|
||||
let Json.417 : U8 = CallByName Num.123 Json.418;
|
||||
let Json.414 : List U8 = CallByName List.4 Json.136 Json.417;
|
||||
jump Json.415 Json.414;
|
||||
let Json.417 : U64 = 1i64;
|
||||
let Json.414 : Int1 = CallByName Num.24 Json.133 Json.417;
|
||||
if Json.414 then
|
||||
let Json.416 : I64 = 44i64;
|
||||
let Json.415 : U8 = CallByName Num.125 Json.416;
|
||||
let Json.412 : List U8 = CallByName List.4 Json.135 Json.415;
|
||||
jump Json.413 Json.412;
|
||||
else
|
||||
jump Json.415 Json.136;
|
||||
jump Json.413 Json.135;
|
||||
|
||||
procedure Json.18 (Json.96):
|
||||
let Json.450 : Str = CallByName Encode.22 Json.96;
|
||||
ret Json.450;
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.448 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.448;
|
||||
|
||||
procedure Json.21 (Json.125, Json.126):
|
||||
let Json.398 : {Str, List Str} = Struct {Json.125, Json.126};
|
||||
let Json.397 : {Str, List Str} = CallByName Encode.22 Json.398;
|
||||
ret Json.397;
|
||||
procedure Json.21 (Json.124, Json.125):
|
||||
let Json.396 : {Str, List Str} = Struct {Json.124, Json.125};
|
||||
let Json.395 : {Str, List Str} = CallByName Encode.22 Json.396;
|
||||
ret Json.395;
|
||||
|
||||
procedure Json.97 (Json.98, Json.440, Json.96):
|
||||
let Json.449 : I32 = 34i64;
|
||||
let Json.448 : U8 = CallByName Num.123 Json.449;
|
||||
let Json.446 : List U8 = CallByName List.4 Json.98 Json.448;
|
||||
let Json.447 : List U8 = CallByName Str.12 Json.96;
|
||||
let Json.443 : List U8 = CallByName List.8 Json.446 Json.447;
|
||||
let Json.445 : I32 = 34i64;
|
||||
let Json.444 : U8 = CallByName Num.123 Json.445;
|
||||
let Json.442 : List U8 = CallByName List.4 Json.443 Json.444;
|
||||
ret Json.442;
|
||||
procedure Json.96 (Json.97, Json.438, Json.95):
|
||||
let Json.447 : I64 = 34i64;
|
||||
let Json.446 : U8 = CallByName Num.125 Json.447;
|
||||
let Json.444 : List U8 = CallByName List.4 Json.97 Json.446;
|
||||
let Json.445 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.441 : List U8 = CallByName List.8 Json.444 Json.445;
|
||||
let Json.443 : I64 = 34i64;
|
||||
let Json.442 : U8 = CallByName Num.125 Json.443;
|
||||
let Json.440 : List U8 = CallByName List.4 Json.441 Json.442;
|
||||
ret Json.440;
|
||||
|
||||
procedure List.133 (List.134, List.135, List.132):
|
||||
let List.432 : {List U8, U64} = CallByName Json.129 List.134 List.135;
|
||||
ret List.432;
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.461 : {List U8, U64} = CallByName Json.128 List.138 List.139;
|
||||
ret List.461;
|
||||
|
||||
procedure List.18 (List.130, List.131, List.132):
|
||||
let List.414 : {List U8, U64} = CallByName List.75 List.130 List.131 List.132;
|
||||
ret List.414;
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.443 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.443;
|
||||
|
||||
procedure List.4 (List.101, List.102):
|
||||
let List.413 : U64 = 1i64;
|
||||
let List.412 : List U8 = CallByName List.70 List.101 List.413;
|
||||
let List.411 : List U8 = CallByName List.71 List.412 List.102;
|
||||
ret List.411;
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.442 : U64 = 1i64;
|
||||
let List.441 : List U8 = CallByName List.70 List.105 List.442;
|
||||
let List.440 : List U8 = CallByName List.71 List.441 List.106;
|
||||
ret List.440;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.380 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.380;
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.433 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.433;
|
||||
let List.462 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.462;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.429 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.429;
|
||||
let List.458 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.458;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.386 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.386;
|
||||
let List.415 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.415;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.384 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.384;
|
||||
|
||||
procedure List.75 (List.356, List.357, List.358):
|
||||
let List.418 : U64 = 0i64;
|
||||
let List.419 : U64 = CallByName List.6 List.356;
|
||||
let List.417 : {List U8, U64} = CallByName List.86 List.356 List.357 List.358 List.418 List.419;
|
||||
ret List.417;
|
||||
let List.413 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.435 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.435;
|
||||
let List.464 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.464;
|
||||
|
||||
procedure List.86 (List.445, List.446, List.447, List.448, List.449):
|
||||
joinpoint List.420 List.359 List.360 List.361 List.362 List.363:
|
||||
let List.422 : Int1 = CallByName Num.22 List.362 List.363;
|
||||
if List.422 then
|
||||
let List.428 : Str = CallByName List.66 List.359 List.362;
|
||||
let List.423 : {List U8, U64} = CallByName List.133 List.360 List.428 List.361;
|
||||
let List.426 : U64 = 1i64;
|
||||
let List.425 : U64 = CallByName Num.19 List.362 List.426;
|
||||
jump List.420 List.359 List.423 List.361 List.425 List.363;
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.447 : U64 = 0i64;
|
||||
let List.448 : U64 = CallByName List.6 List.385;
|
||||
let List.446 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.447 List.448;
|
||||
ret List.446;
|
||||
|
||||
procedure List.90 (List.474, List.475, List.476, List.477, List.478):
|
||||
joinpoint List.449 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.451 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.451 then
|
||||
let List.457 : Str = CallByName List.66 List.388 List.391;
|
||||
let List.452 : {List U8, U64} = CallByName List.137 List.389 List.457 List.390;
|
||||
let List.455 : U64 = 1i64;
|
||||
let List.454 : U64 = CallByName Num.19 List.391 List.455;
|
||||
jump List.449 List.388 List.452 List.390 List.454 List.392;
|
||||
else
|
||||
ret List.360;
|
||||
ret List.389;
|
||||
in
|
||||
jump List.420 List.445 List.446 List.447 List.448 List.449;
|
||||
jump List.449 List.474 List.475 List.476 List.477 List.478;
|
||||
|
||||
procedure Num.123 (#Attr.2):
|
||||
let Num.266 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.266;
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.265 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.265;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.269 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.269;
|
||||
|
||||
procedure Num.20 (#Attr.2, #Attr.3):
|
||||
let Num.267 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.267;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.270 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.270;
|
||||
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Num.268 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||
let Num.268 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.268;
|
||||
|
||||
procedure Num.20 (#Attr.2, #Attr.3):
|
||||
let Num.266 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.266;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.269 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.269;
|
||||
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Num.267 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||
ret Num.267;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.266 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.266;
|
||||
let Str.280 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.280;
|
||||
|
||||
procedure Str.48 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let Str.260 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.260;
|
||||
let Str.274 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8Range #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.274;
|
||||
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.258 : U64 = 0i64;
|
||||
let Str.259 : U64 = CallByName List.6 Str.73;
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.48 Str.73 Str.258 Str.259;
|
||||
let Str.255 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.255 then
|
||||
let Str.257 : Str = StructAtIndex 1 Str.74;
|
||||
inc Str.257;
|
||||
dec Str.74;
|
||||
let Str.256 : [C {U64, U8}, C Str] = TagId(1) Str.257;
|
||||
ret Str.256;
|
||||
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.253 : U8 = StructAtIndex 3 Str.74;
|
||||
let Str.254 : U64 = StructAtIndex 0 Str.74;
|
||||
dec Str.74;
|
||||
let Str.252 : {U64, U8} = Struct {Str.254, Str.253};
|
||||
let Str.251 : [C {U64, U8}, C Str] = TagId(0) Str.252;
|
||||
ret Str.251;
|
||||
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.0 ():
|
||||
let Test.13 : Str = "foo";
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
procedure Num.20 (#Attr.2, #Attr.3):
|
||||
let Num.258 : I64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.258;
|
||||
let Num.257 : I64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.257;
|
||||
|
||||
procedure Num.21 (#Attr.2, #Attr.3):
|
||||
let Num.257 : I64 = lowlevel NumMul #Attr.2 #Attr.3;
|
||||
ret Num.257;
|
||||
let Num.256 : I64 = lowlevel NumMul #Attr.2 #Attr.3;
|
||||
ret Num.256;
|
||||
|
||||
procedure Test.1 (Test.15, Test.16):
|
||||
joinpoint Test.7 Test.2 Test.3:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Bool.1 ():
|
||||
let Bool.11 : Int1 = false;
|
||||
ret Bool.11;
|
||||
let Bool.23 : Int1 = false;
|
||||
ret Bool.23;
|
||||
|
||||
procedure Test.1 (Test.2):
|
||||
let Test.5 : I64 = 2i64;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Bool.7 (#Attr.2, #Attr.3):
|
||||
let Bool.11 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.11;
|
||||
procedure Bool.11 (#Attr.2, #Attr.3):
|
||||
let Bool.23 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.23;
|
||||
|
||||
procedure Test.1 (Test.3):
|
||||
let Test.6 : I64 = 10i64;
|
||||
|
@ -13,7 +13,7 @@ procedure Test.1 (Test.3):
|
|||
ret Test.11;
|
||||
in
|
||||
let Test.10 : I64 = 5i64;
|
||||
let Test.9 : Int1 = CallByName Bool.7 Test.6 Test.10;
|
||||
let Test.9 : Int1 = CallByName Bool.11 Test.6 Test.10;
|
||||
jump Test.8 Test.9;
|
||||
|
||||
procedure Test.0 ():
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
procedure Bool.1 ():
|
||||
let Bool.11 : Int1 = false;
|
||||
ret Bool.11;
|
||||
let Bool.23 : Int1 = false;
|
||||
ret Bool.23;
|
||||
|
||||
procedure Bool.2 ():
|
||||
let Bool.12 : Int1 = true;
|
||||
ret Bool.12;
|
||||
let Bool.24 : Int1 = true;
|
||||
ret Bool.24;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.4 : Int1 = CallByName Bool.2;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
procedure List.6 (#Attr.2):
|
||||
let List.380 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.380;
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.259 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.259;
|
||||
let Num.258 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.258;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.1 : List I64 = Array [1i64, 2i64];
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.257 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.257;
|
||||
let Num.256 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.256;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.2 : I64 = 1i64;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Num.45 (#Attr.2):
|
||||
let Num.257 : I64 = lowlevel NumRound #Attr.2;
|
||||
ret Num.257;
|
||||
let Num.256 : I64 = lowlevel NumRound #Attr.2;
|
||||
ret Num.256;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.2 : Float64 = 3.6f64;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.257 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.257;
|
||||
let Num.256 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.256;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.1 : I64 = 3i64;
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
procedure Bool.7 (#Attr.2, #Attr.3):
|
||||
let Bool.11 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.11;
|
||||
procedure Num.30 (#Attr.2):
|
||||
let Num.263 : I64 = 0i64;
|
||||
let Num.262 : Int1 = lowlevel Eq #Attr.2 Num.263;
|
||||
ret Num.262;
|
||||
|
||||
procedure Num.39 (#Attr.2, #Attr.3):
|
||||
let Num.259 : I64 = lowlevel NumDivTruncUnchecked #Attr.2 #Attr.3;
|
||||
ret Num.259;
|
||||
let Num.258 : I64 = lowlevel NumDivTruncUnchecked #Attr.2 #Attr.3;
|
||||
ret Num.258;
|
||||
|
||||
procedure Num.40 (Num.229, Num.230):
|
||||
let Num.263 : I64 = 0i64;
|
||||
let Num.260 : Int1 = CallByName Bool.7 Num.230 Num.263;
|
||||
if Num.260 then
|
||||
let Num.262 : {} = Struct {};
|
||||
let Num.261 : [C {}, C I64] = TagId(0) Num.262;
|
||||
ret Num.261;
|
||||
procedure Num.40 (Num.228, Num.229):
|
||||
let Num.259 : Int1 = CallByName Num.30 Num.229;
|
||||
if Num.259 then
|
||||
let Num.261 : {} = Struct {};
|
||||
let Num.260 : [C {}, C I64] = TagId(0) Num.261;
|
||||
ret Num.260;
|
||||
else
|
||||
let Num.258 : I64 = CallByName Num.39 Num.229 Num.230;
|
||||
let Num.257 : [C {}, C I64] = TagId(1) Num.258;
|
||||
ret Num.257;
|
||||
let Num.257 : I64 = CallByName Num.39 Num.228 Num.229;
|
||||
let Num.256 : [C {}, C I64] = TagId(1) Num.257;
|
||||
ret Num.256;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.8 : I64 = 1000i64;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.257 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.257;
|
||||
let Num.256 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.256;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.10 : I64 = 41i64;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue