Merge remote-tracking branch 'origin/trunk' into single-quote-literal

This commit is contained in:
Brendan Hansknecht 2022-02-25 07:39:58 -08:00
commit cd0d89fdc9
16 changed files with 405 additions and 98 deletions

117
Cargo.lock generated
View file

@ -24,7 +24,7 @@ version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
dependencies = [ dependencies = [
"gimli", "gimli 0.26.1",
] ]
[[package]] [[package]]
@ -739,6 +739,66 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "cranelift-bforest"
version = "0.74.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8ca3560686e7c9c7ed7e0fe77469f2410ba5d7781b1acaa9adc8d8deea28e3e"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
version = "0.74.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf9bf1ffffb6ce3d2e5ebc83549bd2436426c99b31cc550d521364cbe35d276"
dependencies = [
"cranelift-bforest",
"cranelift-codegen-meta",
"cranelift-codegen-shared",
"cranelift-entity",
"gimli 0.24.0",
"log",
"regalloc",
"smallvec",
"target-lexicon",
]
[[package]]
name = "cranelift-codegen-meta"
version = "0.74.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cc21936a5a6d07e23849ffe83e5c1f6f50305c074f4b2970ca50c13bf55b821"
dependencies = [
"cranelift-codegen-shared",
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen-shared"
version = "0.74.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca5b6ffaa87560bebe69a5446449da18090b126037920b0c1c6d5945f72faf6b"
[[package]]
name = "cranelift-entity"
version = "0.74.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d6b4a8bef04f82e4296782646f733c641d09497df2fabf791323fefaa44c64c"
[[package]]
name = "cranelift-frontend"
version = "0.74.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c31b783b351f966fce33e3c03498cb116d16d97a8f9978164a60920bd0d3a99c"
dependencies = [
"cranelift-codegen",
"log",
"smallvec",
"target-lexicon",
]
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.2.1" version = "1.2.1"
@ -1252,6 +1312,12 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]] [[package]]
name = "fd-lock" name = "fd-lock"
version = "3.0.2" version = "3.0.2"
@ -1471,6 +1537,17 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "gimli"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189"
dependencies = [
"fallible-iterator",
"indexmap",
"stable_deref_trait",
]
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.26.1" version = "0.26.1"
@ -3079,6 +3156,17 @@ dependencies = [
"redox_syscall", "redox_syscall",
] ]
[[package]]
name = "regalloc"
version = "0.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "571f7f397d61c4755285cd37853fe8e03271c243424a907415909379659381c5"
dependencies = [
"log",
"rustc-hash",
"smallvec",
]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.5.4" version = "1.5.4"
@ -4165,6 +4253,12 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]] [[package]]
name = "static_assertions" name = "static_assertions"
version = "1.1.0" version = "1.1.0"
@ -4692,6 +4786,7 @@ dependencies = [
"target-lexicon", "target-lexicon",
"thiserror", "thiserror",
"wasmer-compiler", "wasmer-compiler",
"wasmer-compiler-cranelift",
"wasmer-compiler-singlepass", "wasmer-compiler-singlepass",
"wasmer-derive", "wasmer-derive",
"wasmer-engine", "wasmer-engine",
@ -4721,6 +4816,26 @@ dependencies = [
"wasmparser", "wasmparser",
] ]
[[package]]
name = "wasmer-compiler-cranelift"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a570746cbec434179e2d53357973a34dfdb208043104e8fac3b7b0023015cf6"
dependencies = [
"cranelift-codegen",
"cranelift-entity",
"cranelift-frontend",
"gimli 0.24.0",
"loupe",
"more-asserts",
"rayon",
"smallvec",
"tracing",
"wasmer-compiler",
"wasmer-types",
"wasmer-vm",
]
[[package]] [[package]]
name = "wasmer-compiler-singlepass" name = "wasmer-compiler-singlepass"
version = "2.0.0" version = "2.0.0"

View file

@ -65,12 +65,16 @@ mimalloc = { version = "0.1.26", default-features = false }
target-lexicon = "0.12.2" target-lexicon = "0.12.2"
tempfile = "3.2.0" tempfile = "3.2.0"
wasmer = { version = "2.0.0", optional = true, default-features = false, features = ["default-singlepass", "default-universal"] }
wasmer-wasi = { version = "2.0.0", optional = true } wasmer-wasi = { version = "2.0.0", optional = true }
# Wasmer singlepass compiler only works on x86_64.
[target.'cfg(target_arch = "x86_64")'.dependencies]
wasmer = { version = "2.0.0", optional = true, default-features = false, features = ["default-singlepass", "default-universal"] }
[target.'cfg(not(target_arch = "x86_64"))'.dependencies]
wasmer = { version = "2.0.0", optional = true, default-features = false, features = ["default-cranelift", "default-universal"] }
[dev-dependencies] [dev-dependencies]
wasmer = { version = "2.0.0", default-features = false, features = ["default-singlepass", "default-universal"] }
wasmer-wasi = "2.0.0" wasmer-wasi = "2.0.0"
pretty_assertions = "1.0.0" pretty_assertions = "1.0.0"
roc_test_utils = { path = "../test_utils" } roc_test_utils = { path = "../test_utils" }
@ -79,6 +83,13 @@ serial_test = "0.5.1"
criterion = { git = "https://github.com/Anton-4/criterion.rs"} criterion = { git = "https://github.com/Anton-4/criterion.rs"}
cli_utils = { path = "../cli_utils" } cli_utils = { path = "../cli_utils" }
# Wasmer singlepass compiler only works on x86_64.
[target.'cfg(target_arch = "x86_64")'.dev-dependencies]
wasmer = { version = "2.0.0", default-features = false, features = ["default-singlepass", "default-universal"] }
[target.'cfg(not(target_arch = "x86_64"))'.dev-dependencies]
wasmer = { version = "2.0.0", default-features = false, features = ["default-cranelift", "default-universal"] }
[[bench]] [[bench]]
name = "time_bench" name = "time_bench"
harness = false harness = false

View file

@ -25,7 +25,49 @@ use roc_parse::{
}; };
use roc_region::all::{Loc, Region}; use roc_region::all::{Loc, Region};
fn flatten_directories(files: std::vec::Vec<PathBuf>) -> std::vec::Vec<PathBuf> {
let mut to_flatten = files;
let mut files = vec![];
while let Some(path) = to_flatten.pop() {
if path.is_dir() {
match path.read_dir() {
Ok(directory) => {
for item in directory {
match item {
Ok(file) => {
let file_path = file.path();
if file_path.is_dir() {
to_flatten.push(file_path);
} else if file_path.ends_with(".roc") {
files.push(file_path);
}
}
Err(error) => internal_error!(
"There was an error while trying to read a file from a directory: {:?}",
error
),
}
}
}
Err(error) => internal_error!(
"There was an error while trying to read the contents of a directory: {:?}",
error
),
}
} else {
files.push(path)
}
}
files
}
pub fn format(files: std::vec::Vec<PathBuf>, mode: FormatMode) -> Result<(), String> { pub fn format(files: std::vec::Vec<PathBuf>, mode: FormatMode) -> Result<(), String> {
let files = flatten_directories(files);
for file in files { for file in files {
let arena = Bump::new(); let arena = Bump::new();

View file

@ -5,6 +5,7 @@ use build::{BuildOutcome, BuiltFile};
use bumpalo::Bump; use bumpalo::Bump;
use clap::{App, AppSettings, Arg, ArgMatches}; use clap::{App, AppSettings, Arg, ArgMatches};
use roc_build::link::LinkType; use roc_build::link::LinkType;
use roc_error_macros::user_error;
use roc_load::file::LoadingProblem; use roc_load::file::LoadingProblem;
use roc_mono::ir::OptLevel; use roc_mono::ir::OptLevel;
use std::env; use std::env;
@ -31,6 +32,7 @@ pub const CMD_FORMAT: &str = "format";
pub const FLAG_DEBUG: &str = "debug"; pub const FLAG_DEBUG: &str = "debug";
pub const FLAG_DEV: &str = "dev"; pub const FLAG_DEV: &str = "dev";
pub const FLAG_OPTIMIZE: &str = "optimize"; pub const FLAG_OPTIMIZE: &str = "optimize";
pub const FLAG_OPT_SIZE: &str = "opt-size";
pub const FLAG_LIB: &str = "lib"; pub const FLAG_LIB: &str = "lib";
pub const FLAG_BACKEND: &str = "backend"; pub const FLAG_BACKEND: &str = "backend";
pub const FLAG_TIME: &str = "time"; pub const FLAG_TIME: &str = "time";
@ -61,6 +63,12 @@ pub fn build_app<'a>() -> App<'a> {
.about("Optimize your compiled Roc program to run faster. (Optimization takes time to complete.)") .about("Optimize your compiled Roc program to run faster. (Optimization takes time to complete.)")
.required(false), .required(false),
) )
.arg(
Arg::new(FLAG_OPT_SIZE)
.long(FLAG_OPT_SIZE)
.about("Optimize your compiled Roc program to have a small binary size. (Optimization takes time to complete.)")
.required(false),
)
.arg( .arg(
Arg::new(FLAG_DEV) Arg::new(FLAG_DEV)
.long(FLAG_DEV) .long(FLAG_DEV)
@ -166,6 +174,12 @@ pub fn build_app<'a>() -> App<'a> {
.requires(ROC_FILE) .requires(ROC_FILE)
.required(false), .required(false),
) )
.arg(
Arg::new(FLAG_OPT_SIZE)
.long(FLAG_OPT_SIZE)
.about("Optimize your compiled Roc program to have a small binary size. (Optimization takes time to complete.)")
.required(false),
)
.arg( .arg(
Arg::new(FLAG_DEV) Arg::new(FLAG_DEV)
.long(FLAG_DEV) .long(FLAG_DEV)
@ -272,12 +286,14 @@ pub fn build(matches: &ArgMatches, config: BuildConfig) -> io::Result<i32> {
let original_cwd = std::env::current_dir()?; let original_cwd = std::env::current_dir()?;
let opt_level = match ( let opt_level = match (
matches.is_present(FLAG_OPTIMIZE), matches.is_present(FLAG_OPTIMIZE),
matches.is_present(FLAG_OPT_SIZE),
matches.is_present(FLAG_DEV), matches.is_present(FLAG_DEV),
) { ) {
(true, false) => OptLevel::Optimize, (true, false, false) => OptLevel::Optimize,
(true, true) => panic!("development cannot be optimized!"), (false, true, false) => OptLevel::Size,
(false, true) => OptLevel::Development, (false, false, true) => OptLevel::Development,
(false, false) => OptLevel::Normal, (false, false, false) => OptLevel::Normal,
_ => user_error!("build can be only one of `--dev`, `--optimize`, or `--opt-size`"),
}; };
let emit_debug_info = matches.is_present(FLAG_DEBUG); let emit_debug_info = matches.is_present(FLAG_DEBUG);
let emit_timings = matches.is_present(FLAG_TIME); let emit_timings = matches.is_present(FLAG_TIME);

View file

@ -12,8 +12,8 @@ extern crate indoc;
#[cfg(test)] #[cfg(test)]
mod cli_run { mod cli_run {
use cli_utils::helpers::{ use cli_utils::helpers::{
example_file, examples_dir, extract_valgrind_errors, fixture_file, known_bad_file, run_cmd, example_file, examples_dir, extract_valgrind_errors, fixture_file, fixtures_dir,
run_roc, run_with_valgrind, ValgrindError, ValgrindErrorXWhat, known_bad_file, run_cmd, run_roc, run_with_valgrind, ValgrindError, ValgrindErrorXWhat,
}; };
use roc_test_utils::assert_multiline_str_eq; use roc_test_utils::assert_multiline_str_eq;
use serial_test::serial; use serial_test::serial;
@ -884,6 +884,15 @@ mod cli_run {
fn format_check_reformatting_needed() { fn format_check_reformatting_needed() {
check_format_check_as_expected(&fixture_file("format", "NotFormatted.roc"), false); check_format_check_as_expected(&fixture_file("format", "NotFormatted.roc"), false);
} }
#[test]
fn format_check_folders() {
// This fails, because "NotFormatted.roc" is present in this folder
check_format_check_as_expected(&fixtures_dir("format"), false);
// This doesn't fail, since only "Formatted.roc" is present in this folder
check_format_check_as_expected(&fixtures_dir("format/formatted_directory"), true);
}
} }
#[allow(dead_code)] #[allow(dead_code)]

View file

@ -0,0 +1,6 @@
app "formatted"
packages { pf: "platform" } imports []
provides [ main ] to pf
main : Str
main = Dep1.value1 {}

View file

@ -137,6 +137,8 @@ pub fn build_zig_host_native(
if matches!(opt_level, OptLevel::Optimize) { if matches!(opt_level, OptLevel::Optimize) {
command.args(&["-O", "ReleaseSafe"]); command.args(&["-O", "ReleaseSafe"]);
} else if matches!(opt_level, OptLevel::Size) {
command.args(&["-O", "ReleaseSmall"]);
} }
command.output().unwrap() command.output().unwrap()
} }
@ -231,6 +233,8 @@ pub fn build_zig_host_native(
]); ]);
if matches!(opt_level, OptLevel::Optimize) { if matches!(opt_level, OptLevel::Optimize) {
command.args(&["-O", "ReleaseSafe"]); command.args(&["-O", "ReleaseSafe"]);
} else if matches!(opt_level, OptLevel::Size) {
command.args(&["-O", "ReleaseSmall"]);
} }
command.output().unwrap() command.output().unwrap()
} }
@ -282,6 +286,8 @@ pub fn build_zig_host_wasm32(
]); ]);
if matches!(opt_level, OptLevel::Optimize) { if matches!(opt_level, OptLevel::Optimize) {
command.args(&["-O", "ReleaseSafe"]); command.args(&["-O", "ReleaseSafe"]);
} else if matches!(opt_level, OptLevel::Size) {
command.args(&["-O", "ReleaseSmall"]);
} }
command.output().unwrap() command.output().unwrap()
} }
@ -317,7 +323,9 @@ pub fn build_c_host_native(
command.args(&["-fPIC", "-c"]); command.args(&["-fPIC", "-c"]);
} }
if matches!(opt_level, OptLevel::Optimize) { if matches!(opt_level, OptLevel::Optimize) {
command.arg("-O2"); command.arg("-O3");
} else if matches!(opt_level, OptLevel::Size) {
command.arg("-Os");
} }
command.output().unwrap() command.output().unwrap()
} }
@ -351,6 +359,8 @@ pub fn build_swift_host_native(
if matches!(opt_level, OptLevel::Optimize) { if matches!(opt_level, OptLevel::Optimize) {
command.arg("-O"); command.arg("-O");
} else if matches!(opt_level, OptLevel::Size) {
command.arg("-Osize");
} }
command.output().unwrap() command.output().unwrap()
@ -456,18 +466,18 @@ pub fn rebuild_host(
} else if cargo_host_src.exists() { } else if cargo_host_src.exists() {
// Compile and link Cargo.toml, if it exists // Compile and link Cargo.toml, if it exists
let cargo_dir = host_input_path.parent().unwrap(); let cargo_dir = host_input_path.parent().unwrap();
let cargo_out_dir = let cargo_out_dir = cargo_dir.join("target").join(
cargo_dir if matches!(opt_level, OptLevel::Optimize | OptLevel::Size) {
.join("target")
.join(if matches!(opt_level, OptLevel::Optimize) {
"release" "release"
} else { } else {
"debug" "debug"
}); },
);
let mut command = Command::new("cargo"); let mut command = Command::new("cargo");
command.arg("build").current_dir(cargo_dir); command.arg("build").current_dir(cargo_dir);
if matches!(opt_level, OptLevel::Optimize) { // 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"); command.arg("--release");
} }
let source_file = if shared_lib_path.is_some() { let source_file = if shared_lib_path.is_some() {
@ -533,6 +543,8 @@ pub fn rebuild_host(
]); ]);
if matches!(opt_level, OptLevel::Optimize) { if matches!(opt_level, OptLevel::Optimize) {
command.arg("-O"); command.arg("-O");
} else if matches!(opt_level, OptLevel::Size) {
command.arg("-C opt-level=s");
} }
let output = command.output().unwrap(); let output = command.output().unwrap();

View file

@ -199,7 +199,7 @@ pub fn gen_from_mono_module(
emit_debug_info: bool, emit_debug_info: bool,
) -> CodeGenTiming { ) -> CodeGenTiming {
match opt_level { match opt_level {
OptLevel::Normal | OptLevel::Optimize => gen_from_mono_module_llvm( OptLevel::Normal | OptLevel::Size | OptLevel::Optimize => gen_from_mono_module_llvm(
arena, arena,
loaded, loaded,
roc_file_path, roc_file_path,

View file

@ -114,6 +114,8 @@ pub fn target_machine(
pub fn convert_opt_level(level: OptLevel) -> OptimizationLevel { pub fn convert_opt_level(level: OptLevel) -> OptimizationLevel {
match level { match level {
OptLevel::Development | OptLevel::Normal => OptimizationLevel::None, OptLevel::Development | OptLevel::Normal => OptimizationLevel::None,
// Default is O2/Os. If we want Oz, we have to explicitly turn of loop vectorization as well.
OptLevel::Size => OptimizationLevel::Default,
OptLevel::Optimize => OptimizationLevel::Aggressive, OptLevel::Optimize => OptimizationLevel::Aggressive,
} }
} }

View file

@ -657,11 +657,20 @@ pub fn construct_optimization_passes<'a>(
OptLevel::Development | OptLevel::Normal => { OptLevel::Development | OptLevel::Normal => {
pmb.set_optimization_level(OptimizationLevel::None); pmb.set_optimization_level(OptimizationLevel::None);
} }
OptLevel::Size => {
pmb.set_optimization_level(OptimizationLevel::Default);
// TODO: For some usecase, like embedded, it is useful to expose this and tune it.
pmb.set_inliner_with_threshold(50);
}
OptLevel::Optimize => { OptLevel::Optimize => {
pmb.set_optimization_level(OptimizationLevel::Aggressive); pmb.set_optimization_level(OptimizationLevel::Aggressive);
// this threshold seems to do what we want // this threshold seems to do what we want
pmb.set_inliner_with_threshold(275); pmb.set_inliner_with_threshold(275);
}
}
// Add optimization passes for Size and Optimize.
if matches!(opt_level, OptLevel::Size | OptLevel::Optimize) {
// TODO figure out which of these actually help // TODO figure out which of these actually help
// function passes // function passes
@ -684,7 +693,6 @@ pub fn construct_optimization_passes<'a>(
mpm.add_function_inlining_pass(); mpm.add_function_inlining_pass();
} }
}
pmb.populate_module_pass_manager(&mpm); pmb.populate_module_pass_manager(&mpm);
pmb.populate_function_pass_manager(&fpm); pmb.populate_function_pass_manager(&fpm);

View file

@ -245,7 +245,7 @@ where
match opt_level { match opt_level {
OptLevel::Development | OptLevel::Normal => morphic_lib::solve_trivial(program), OptLevel::Development | OptLevel::Normal => morphic_lib::solve_trivial(program),
OptLevel::Optimize => morphic_lib::solve(program), OptLevel::Optimize | OptLevel::Size => morphic_lib::solve(program),
} }
} }

View file

@ -90,6 +90,7 @@ macro_rules! return_on_layout_error_help {
pub enum OptLevel { pub enum OptLevel {
Development, Development,
Normal, Normal,
Size,
Optimize, Optimize,
} }

View file

@ -39,11 +39,17 @@ libc = "0.2.106"
inkwell = { path = "../../vendor/inkwell" } inkwell = { path = "../../vendor/inkwell" }
target-lexicon = "0.12.2" target-lexicon = "0.12.2"
libloading = "0.7.1" libloading = "0.7.1"
wasmer = { version = "2.0.0", default-features = false, features = ["default-singlepass", "default-universal"] }
wasmer-wasi = "2.0.0" wasmer-wasi = "2.0.0"
tempfile = "3.2.0" tempfile = "3.2.0"
indoc = "1.0.3" indoc = "1.0.3"
# Wasmer singlepass compiler only works on x86_64.
[target.'cfg(target_arch = "x86_64")'.dev-dependencies]
wasmer = { version = "2.0.0", default-features = false, features = ["default-singlepass", "default-universal"] }
[target.'cfg(not(target_arch = "x86_64"))'.dev-dependencies]
wasmer = { version = "2.0.0", default-features = false, features = ["default-cranelift", "default-universal"] }
[features] [features]
default = ["gen-llvm"] default = ["gen-llvm"]
gen-llvm = [] gen-llvm = []

View file

@ -28,7 +28,7 @@ fn roc_list_construction() {
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn empty_list_literal() { fn empty_list_literal() {
assert_evals_to!("[]", RocList::from_slice(&[]), RocList<i64>); assert_evals_to!("[]", RocList::<i64>::from_slice(&[]), RocList<i64>);
} }
#[test] #[test]
@ -136,7 +136,7 @@ fn bool_list_literal() {
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn variously_sized_list_literals() { fn variously_sized_list_literals() {
assert_evals_to!("[]", RocList::from_slice(&[]), RocList<i64>); assert_evals_to!("[]", RocList::<i64>::from_slice(&[]), RocList<i64>);
assert_evals_to!("[1]", RocList::from_slice(&[1]), RocList<i64>); assert_evals_to!("[1]", RocList::from_slice(&[1]), RocList<i64>);
assert_evals_to!("[1, 2]", RocList::from_slice(&[1, 2]), RocList<i64>); assert_evals_to!("[1, 2]", RocList::from_slice(&[1, 2]), RocList<i64>);
assert_evals_to!("[1, 2, 3]", RocList::from_slice(&[1, 2, 3]), RocList<i64>); assert_evals_to!("[1, 2, 3]", RocList::from_slice(&[1, 2, 3]), RocList<i64>);
@ -177,12 +177,12 @@ fn list_take_first() {
); );
assert_evals_to!( assert_evals_to!(
"List.takeFirst [1, 2, 3] 0", "List.takeFirst [1, 2, 3] 0",
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
assert_evals_to!( assert_evals_to!(
"List.takeFirst [] 1", "List.takeFirst [] 1",
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
assert_evals_to!( assert_evals_to!(
@ -202,10 +202,14 @@ fn list_take_last() {
); );
assert_evals_to!( assert_evals_to!(
"List.takeLast [1, 2, 3] 0", "List.takeLast [1, 2, 3] 0",
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64>
);
assert_evals_to!(
"List.takeLast [] 1",
RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
assert_evals_to!("List.takeLast [] 1", RocList::from_slice(&[]), RocList<i64>);
assert_evals_to!( assert_evals_to!(
"List.takeLast [1,2] 5", "List.takeLast [1,2] 5",
RocList::from_slice(&[1, 2]), RocList::from_slice(&[1, 2]),
@ -233,17 +237,17 @@ fn list_sublist() {
); );
assert_evals_to!( assert_evals_to!(
"List.sublist [1, 2, 3] { start: 3 , len: 2 } ", "List.sublist [1, 2, 3] { start: 3 , len: 2 } ",
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
assert_evals_to!( assert_evals_to!(
"List.sublist [] { start: 1 , len: 1 } ", "List.sublist [] { start: 1 , len: 1 } ",
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
assert_evals_to!( assert_evals_to!(
"List.sublist [1, 2, 3] { start: 1 , len: 0 } ", "List.sublist [1, 2, 3] { start: 1 , len: 0 } ",
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
assert_evals_to!( assert_evals_to!(
@ -261,7 +265,7 @@ fn list_split() {
list = List.split [1, 2, 3] 0 list = List.split [1, 2, 3] 0
list.before list.before
"#, "#,
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
assert_evals_to!( assert_evals_to!(
@ -280,17 +284,26 @@ fn list_split() {
); );
assert_evals_to!( assert_evals_to!(
"List.split [1, 2, 3] 3", "List.split [1, 2, 3] 3",
(RocList::from_slice(&[1, 2, 3]), RocList::from_slice(&[]),), (
RocList::from_slice(&[1, 2, 3]),
RocList::<i64>::from_slice(&[]),
),
(RocList<i64>, RocList<i64>,) (RocList<i64>, RocList<i64>,)
); );
assert_evals_to!( assert_evals_to!(
"List.split [1, 2, 3] 4", "List.split [1, 2, 3] 4",
(RocList::from_slice(&[1, 2, 3]), RocList::from_slice(&[]),), (
RocList::from_slice(&[1, 2, 3]),
RocList::<i64>::from_slice(&[]),
),
(RocList<i64>, RocList<i64>,) (RocList<i64>, RocList<i64>,)
); );
assert_evals_to!( assert_evals_to!(
"List.split [] 1", "List.split [] 1",
(RocList::from_slice(&[]), RocList::from_slice(&[]),), (
RocList::<i64>::from_slice(&[]),
RocList::<i64>::from_slice(&[]),
),
(RocList<i64>, RocList<i64>,) (RocList<i64>, RocList<i64>,)
); );
} }
@ -302,8 +315,16 @@ fn list_drop() {
RocList::from_slice(&[3]), RocList::from_slice(&[3]),
RocList<i64> RocList<i64>
); );
assert_evals_to!("List.drop [] 1", RocList::from_slice(&[]), RocList<i64>); assert_evals_to!(
assert_evals_to!("List.drop [1,2] 5", RocList::from_slice(&[]), RocList<i64>); "List.drop [] 1",
RocList::<i64>::from_slice(&[]),
RocList<i64>
);
assert_evals_to!(
"List.drop [1,2] 5",
RocList::<i64>::from_slice(&[]),
RocList<i64>
);
} }
#[test] #[test]
@ -319,8 +340,16 @@ fn list_drop_at() {
RocList::from_slice(&[0, 0, 0]), RocList::from_slice(&[0, 0, 0]),
RocList<i64> RocList<i64>
); );
assert_evals_to!("List.dropAt [] 1", RocList::from_slice(&[]), RocList<i64>); assert_evals_to!(
assert_evals_to!("List.dropAt [0] 0", RocList::from_slice(&[]), RocList<i64>); "List.dropAt [] 1",
RocList::<i64>::from_slice(&[]),
RocList<i64>
);
assert_evals_to!(
"List.dropAt [0] 0",
RocList::<i64>::from_slice(&[]),
RocList<i64>
);
} }
#[test] #[test]
@ -341,7 +370,7 @@ fn list_intersperse() {
List.intersperse [] 1 List.intersperse [] 1
"# "#
), ),
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
} }
@ -380,7 +409,7 @@ fn list_drop_if_empty_list_of_int() {
List.dropIf empty \_ -> True List.dropIf empty \_ -> True
"# "#
), ),
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
} }
@ -397,7 +426,7 @@ fn list_drop_if_empty_list() {
List.dropIf [] alwaysTrue List.dropIf [] alwaysTrue
"# "#
), ),
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
} }
@ -425,7 +454,7 @@ fn list_drop_if_always_true_for_non_empty_list() {
List.dropIf [1,2,3,4,5,6,7,8] (\_ -> True) List.dropIf [1,2,3,4,5,6,7,8] (\_ -> True)
"# "#
), ),
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
} }
@ -466,8 +495,16 @@ fn list_drop_last() {
RocList::from_slice(&[1, 2]), RocList::from_slice(&[1, 2]),
RocList<i64> RocList<i64>
); );
assert_evals_to!("List.dropLast []", RocList::from_slice(&[]), RocList<i64>); assert_evals_to!(
assert_evals_to!("List.dropLast [0]", RocList::from_slice(&[]), RocList<i64>); "List.dropLast []",
RocList::<i64>::from_slice(&[]),
RocList<i64>
);
assert_evals_to!(
"List.dropLast [0]",
RocList::<i64>::from_slice(&[]),
RocList<i64>
);
} }
#[test] #[test]
@ -500,14 +537,26 @@ fn list_drop_first() {
RocList::from_slice(&[2, 3]), RocList::from_slice(&[2, 3]),
RocList<i64> RocList<i64>
); );
assert_evals_to!("List.dropFirst []", RocList::from_slice(&[]), RocList<i64>); assert_evals_to!(
assert_evals_to!("List.dropFirst [0]", RocList::from_slice(&[]), RocList<i64>); "List.dropFirst []",
RocList::<i64>::from_slice(&[]),
RocList<i64>
);
assert_evals_to!(
"List.dropFirst [0]",
RocList::<i64>::from_slice(&[]),
RocList<i64>
);
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn list_swap() { fn list_swap() {
assert_evals_to!("List.swap [] 0 1", RocList::from_slice(&[]), RocList<i64>); assert_evals_to!(
"List.swap [] 0 1",
RocList::<i64>::from_slice(&[]),
RocList<i64>
);
assert_evals_to!( assert_evals_to!(
"List.swap [ 0 ] 1 2", "List.swap [ 0 ] 1 2",
RocList::from_slice(&[0]), RocList::from_slice(&[0]),
@ -780,7 +829,7 @@ fn list_keep_if_empty_list_of_int() {
List.keepIf empty \_ -> True List.keepIf empty \_ -> True
"# "#
), ),
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
} }
@ -799,7 +848,7 @@ fn list_keep_if_empty_list() {
List.keepIf [] alwaysTrue List.keepIf [] alwaysTrue
"# "#
), ),
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
} }
@ -839,7 +888,7 @@ fn list_keep_if_always_false_for_non_empty_list() {
List.keepIf [1,2,3,4,5,6,7,8] alwaysFalse List.keepIf [1,2,3,4,5,6,7,8] alwaysFalse
"# "#
), ),
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
} }
@ -889,7 +938,7 @@ fn list_map_on_empty_list_with_int_layout() {
List.map empty (\x -> x) List.map empty (\x -> x)
"# "#
), ),
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
} }
@ -1000,7 +1049,7 @@ fn list_map_all_inline() {
List.map [] (\x -> x > 0) List.map [] (\x -> x > 0)
"# "#
), ),
RocList::from_slice(&[]), RocList::<bool>::from_slice(&[]),
RocList<bool> RocList<bool>
); );
} }
@ -1126,7 +1175,11 @@ fn list_map2_different_lengths() {
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn list_join_empty_list() { fn list_join_empty_list() {
assert_evals_to!("List.join []", RocList::from_slice(&[]), RocList<i64>); assert_evals_to!(
"List.join []",
RocList::<i64>::from_slice(&[]),
RocList<i64>
);
} }
#[test] #[test]
@ -1208,7 +1261,7 @@ fn list_join_defined_empty_list() {
fn list_join_all_empty_lists() { fn list_join_all_empty_lists() {
assert_evals_to!( assert_evals_to!(
"List.join [ [], [], [] ]", "List.join [ [], [], [] ]",
RocList::from_slice(&[]), RocList::<f64>::from_slice(&[]),
RocList<f64> RocList<f64>
); );
} }
@ -1246,7 +1299,7 @@ fn list_repeat() {
assert_evals_to!( assert_evals_to!(
"List.repeat [] 2", "List.repeat [] 2",
RocList::from_slice(&[RocList::default(), RocList::default()]), RocList::from_slice(&[RocList::<i64>::default(), RocList::default()]),
RocList<RocList<i64>> RocList<RocList<i64>>
); );
@ -1260,7 +1313,7 @@ fn list_repeat() {
List.repeat noStrs 2 List.repeat noStrs 2
"# "#
), ),
RocList::from_slice(&[RocList::default(), RocList::default()]), RocList::from_slice(&[RocList::<i64>::default(), RocList::default()]),
RocList<RocList<i64>> RocList<RocList<i64>>
); );
@ -1300,7 +1353,7 @@ fn list_reverse_empty_list_of_int() {
List.reverse emptyList List.reverse emptyList
"# "#
), ),
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
} }
@ -1308,7 +1361,11 @@ fn list_reverse_empty_list_of_int() {
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn list_reverse_empty_list() { fn list_reverse_empty_list() {
assert_evals_to!("List.reverse []", RocList::from_slice(&[]), RocList<i64>); assert_evals_to!(
"List.reverse []",
RocList::<i64>::from_slice(&[]),
RocList<i64>
);
} }
#[test] #[test]
@ -1328,7 +1385,7 @@ fn list_concat() {
List.concat firstList secondList List.concat firstList secondList
"# "#
), ),
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
} }
@ -1336,7 +1393,11 @@ fn list_concat() {
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn list_concat_two_empty_lists() { fn list_concat_two_empty_lists() {
assert_evals_to!("List.concat [] []", RocList::from_slice(&[]), RocList<i64>); assert_evals_to!(
"List.concat [] []",
RocList::<i64>::from_slice(&[]),
RocList<i64>
);
} }
#[test] #[test]
@ -1356,7 +1417,7 @@ fn list_concat_two_empty_lists_of_int() {
List.concat firstList secondList List.concat firstList secondList
"# "#
), ),
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
} }
@ -2386,7 +2447,11 @@ fn cleanup_because_exception() {
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn list_range() { fn list_range() {
assert_evals_to!("List.range 0 -1", RocList::from_slice(&[]), RocList<i64>); assert_evals_to!(
"List.range 0 -1",
RocList::<i64>::from_slice(&[]),
RocList<i64>
);
assert_evals_to!("List.range 0 0", RocList::from_slice(&[0]), RocList<i64>); assert_evals_to!("List.range 0 0", RocList::from_slice(&[0]), RocList<i64>);
assert_evals_to!( assert_evals_to!(
"List.range 0 5", "List.range 0 5",
@ -2400,7 +2465,7 @@ fn list_range() {
fn list_sort_with() { fn list_sort_with() {
assert_evals_to!( assert_evals_to!(
"List.sortWith [] Num.compare", "List.sortWith [] Num.compare",
RocList::from_slice(&[]), RocList::<i64>::from_slice(&[]),
RocList<i64> RocList<i64>
); );
assert_evals_to!( assert_evals_to!(
@ -2418,7 +2483,11 @@ fn list_sort_with() {
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn list_sort_asc() { fn list_sort_asc() {
assert_evals_to!("List.sortAsc []", RocList::from_slice(&[]), RocList<i64>); assert_evals_to!(
"List.sortAsc []",
RocList::<i64>::from_slice(&[]),
RocList<i64>
);
assert_evals_to!( assert_evals_to!(
"List.sortAsc [ 4,3,2,1 ]", "List.sortAsc [ 4,3,2,1 ]",
RocList::from_slice(&[1, 2, 3, 4]), RocList::from_slice(&[1, 2, 3, 4]),
@ -2429,7 +2498,11 @@ fn list_sort_asc() {
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn list_sort_desc() { fn list_sort_desc() {
assert_evals_to!("List.sortDesc []", RocList::from_slice(&[]), RocList<i64>); assert_evals_to!(
"List.sortDesc []",
RocList::<i64>::from_slice(&[]),
RocList<i64>
);
assert_evals_to!( assert_evals_to!(
"List.sortDesc [ 1,2,3,4 ]", "List.sortDesc [ 1,2,3,4 ]",
RocList::from_slice(&[4, 3, 2, 1]), RocList::from_slice(&[4, 3, 2, 1]),

View file

@ -238,7 +238,7 @@ fn from_list() {
|> Set.toList |> Set.toList
"# "#
), ),
RocList::default(), RocList::<i64>::default(),
RocList<i64> RocList<i64>
); );
} }
@ -254,7 +254,7 @@ fn from_list_void() {
|> Set.toList |> Set.toList
"# "#
), ),
RocList::default(), RocList::<i64>::default(),
RocList<i64> RocList<i64>
); );
} }

View file

@ -13,11 +13,17 @@ roc_cli = {path = "../cli"}
[dev-dependencies] [dev-dependencies]
indoc = "1.0.3" indoc = "1.0.3"
strip-ansi-escapes = "0.1.1" strip-ansi-escapes = "0.1.1"
wasmer = {version = "2.0.0", default-features = false, features = ["default-singlepass", "default-universal"]}
wasmer-wasi = "2.0.0" wasmer-wasi = "2.0.0"
roc_repl_cli = {path = "../repl_cli"} roc_repl_cli = {path = "../repl_cli"}
roc_test_utils = {path = "../test_utils"} roc_test_utils = {path = "../test_utils"}
# Wasmer singlepass compiler only works on x86_64.
[target.'cfg(target_arch = "x86_64")'.dev-dependencies]
wasmer = { version = "2.0.0", default-features = false, features = ["default-singlepass", "default-universal"] }
[target.'cfg(not(target_arch = "x86_64"))'.dev-dependencies]
wasmer = { version = "2.0.0", default-features = false, features = ["default-cranelift", "default-universal"] }
[features] [features]
wasm = [] wasm = []