mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
Merge remote-tracking branch 'origin/trunk' into tag-union-imitate-rust
This commit is contained in:
commit
c827256e47
41 changed files with 957 additions and 532 deletions
29
Cargo.lock
generated
29
Cargo.lock
generated
|
@ -3122,8 +3122,6 @@ name = "roc_build"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"im",
|
|
||||||
"im-rc",
|
|
||||||
"inkwell 0.1.0",
|
"inkwell 0.1.0",
|
||||||
"libloading 0.7.1",
|
"libloading 0.7.1",
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
|
@ -3164,8 +3162,6 @@ name = "roc_can"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"im",
|
|
||||||
"im-rc",
|
|
||||||
"indoc",
|
"indoc",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
|
@ -3187,8 +3183,6 @@ dependencies = [
|
||||||
"cli_utils",
|
"cli_utils",
|
||||||
"const_format",
|
"const_format",
|
||||||
"criterion",
|
"criterion",
|
||||||
"im",
|
|
||||||
"im-rc",
|
|
||||||
"indoc",
|
"indoc",
|
||||||
"inkwell 0.1.0",
|
"inkwell 0.1.0",
|
||||||
"libloading 0.7.1",
|
"libloading 0.7.1",
|
||||||
|
@ -3298,8 +3292,6 @@ dependencies = [
|
||||||
"fs_extra",
|
"fs_extra",
|
||||||
"futures",
|
"futures",
|
||||||
"glyph_brush",
|
"glyph_brush",
|
||||||
"im",
|
|
||||||
"im-rc",
|
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"nonempty",
|
"nonempty",
|
||||||
|
@ -3339,8 +3331,6 @@ name = "roc_fmt"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"im",
|
|
||||||
"im-rc",
|
|
||||||
"indoc",
|
"indoc",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
|
@ -3354,8 +3344,6 @@ name = "roc_gen_dev"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"im",
|
|
||||||
"im-rc",
|
|
||||||
"object 0.26.2",
|
"object 0.26.2",
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
"roc_can",
|
"roc_can",
|
||||||
|
@ -3377,22 +3365,13 @@ name = "roc_gen_llvm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"im",
|
|
||||||
"im-rc",
|
|
||||||
"inkwell 0.1.0",
|
"inkwell 0.1.0",
|
||||||
"morphic_lib",
|
"morphic_lib",
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
"roc_can",
|
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_mono",
|
"roc_mono",
|
||||||
"roc_parse",
|
|
||||||
"roc_problem",
|
|
||||||
"roc_region",
|
|
||||||
"roc_solve",
|
|
||||||
"roc_std",
|
"roc_std",
|
||||||
"roc_types",
|
|
||||||
"roc_unify",
|
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -3478,20 +3457,16 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"hashbrown 0.11.2",
|
"hashbrown 0.11.2",
|
||||||
"linked-hash-map",
|
|
||||||
"morphic_lib",
|
"morphic_lib",
|
||||||
"roc_builtins",
|
|
||||||
"roc_can",
|
"roc_can",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_parse",
|
|
||||||
"roc_problem",
|
"roc_problem",
|
||||||
"roc_region",
|
"roc_region",
|
||||||
"roc_solve",
|
"roc_solve",
|
||||||
"roc_std",
|
"roc_std",
|
||||||
"roc_types",
|
"roc_types",
|
||||||
"roc_unify",
|
"roc_unify",
|
||||||
"ven_ena",
|
|
||||||
"ven_graph",
|
"ven_graph",
|
||||||
"ven_pretty",
|
"ven_pretty",
|
||||||
]
|
]
|
||||||
|
@ -3531,8 +3506,6 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"distance",
|
"distance",
|
||||||
"im",
|
|
||||||
"im-rc",
|
|
||||||
"indoc",
|
"indoc",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
|
@ -4074,8 +4047,6 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"either",
|
"either",
|
||||||
"im",
|
|
||||||
"im-rc",
|
|
||||||
"indoc",
|
"indoc",
|
||||||
"inkwell 0.1.0",
|
"inkwell 0.1.0",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
|
@ -111,12 +111,14 @@ test-all:
|
||||||
|
|
||||||
build-nightly-release:
|
build-nightly-release:
|
||||||
FROM +test-rust
|
FROM +test-rust
|
||||||
COPY --dir .git ./
|
COPY --dir .git LICENSE LEGAL_DETAILS ./
|
||||||
# version.txt is used by the CLI: roc --version
|
# version.txt is used by the CLI: roc --version
|
||||||
RUN printf "nightly pre-release, built from commit " > version.txt
|
RUN printf "nightly pre-release, built from commit " > version.txt
|
||||||
RUN git log --pretty=format:'%h' -n 1 >> version.txt
|
RUN git log --pretty=format:'%h' -n 1 >> version.txt
|
||||||
|
RUN printf " on: " >> version.txt
|
||||||
|
RUN date >> version.txt
|
||||||
RUN cargo build --features with_sound --release
|
RUN cargo build --features with_sound --release
|
||||||
RUN cd ./target/release && tar -czvf roc_linux_x86_64.tar.gz ./roc
|
RUN cd ./target/release && tar -czvf roc_linux_x86_64.tar.gz ./roc ../../LICENSE ../../LEGAL_DETAILS ../../examples/hello-world ../../examples/hello-rust ../../examples/hello-zig ../../compiler/builtins/bitcode/src/ ../../roc_std
|
||||||
SAVE ARTIFACT ./target/release/roc_linux_x86_64.tar.gz AS LOCAL roc_linux_x86_64.tar.gz
|
SAVE ARTIFACT ./target/release/roc_linux_x86_64.tar.gz AS LOCAL roc_linux_x86_64.tar.gz
|
||||||
|
|
||||||
# compile everything needed for benchmarks and output a self-contained dir from which benchmarks can be run.
|
# compile everything needed for benchmarks and output a self-contained dir from which benchmarks can be run.
|
||||||
|
|
|
@ -186,6 +186,7 @@ pub fn update_str_expr(
|
||||||
|
|
||||||
let insert_either = match str_expr {
|
let insert_either = match str_expr {
|
||||||
Expr2::SmallStr(arr_string) => {
|
Expr2::SmallStr(arr_string) => {
|
||||||
|
// TODO make sure this works for unicode "characters"
|
||||||
let insert_res = arr_string.try_insert(insert_index as u8, new_char);
|
let insert_res = arr_string.try_insert(insert_index as u8, new_char);
|
||||||
|
|
||||||
match insert_res {
|
match insert_res {
|
||||||
|
|
|
@ -68,8 +68,6 @@ clap = { version = "= 3.0.0-beta.5", default-features = false, features = ["std"
|
||||||
const_format = "0.2.22"
|
const_format = "0.2.22"
|
||||||
rustyline = { git = "https://github.com/rtfeldman/rustyline", tag = "prompt-fix" }
|
rustyline = { git = "https://github.com/rtfeldman/rustyline", tag = "prompt-fix" }
|
||||||
rustyline-derive = { git = "https://github.com/rtfeldman/rustyline", tag = "prompt-fix" }
|
rustyline-derive = { git = "https://github.com/rtfeldman/rustyline", tag = "prompt-fix" }
|
||||||
im = "15.0.0"
|
|
||||||
im-rc = "15.0.0"
|
|
||||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
libloading = "0.7.1"
|
libloading = "0.7.1"
|
||||||
mimalloc = { version = "0.1.26", default-features = false }
|
mimalloc = { version = "0.1.26", default-features = false }
|
||||||
|
|
|
@ -23,6 +23,7 @@ pub const CMD_REPL: &str = "repl";
|
||||||
pub const CMD_EDIT: &str = "edit";
|
pub const CMD_EDIT: &str = "edit";
|
||||||
pub const CMD_DOCS: &str = "docs";
|
pub const CMD_DOCS: &str = "docs";
|
||||||
pub const CMD_CHECK: &str = "check";
|
pub const CMD_CHECK: &str = "check";
|
||||||
|
pub const CMD_VERSION: &str = "version";
|
||||||
|
|
||||||
pub const FLAG_DEBUG: &str = "debug";
|
pub const FLAG_DEBUG: &str = "debug";
|
||||||
pub const FLAG_DEV: &str = "dev";
|
pub const FLAG_DEV: &str = "dev";
|
||||||
|
@ -103,8 +104,11 @@ pub fn build_app<'a>() -> App<'a> {
|
||||||
.subcommand(App::new(CMD_REPL)
|
.subcommand(App::new(CMD_REPL)
|
||||||
.about("Launch the interactive Read Eval Print Loop (REPL)")
|
.about("Launch the interactive Read Eval Print Loop (REPL)")
|
||||||
)
|
)
|
||||||
|
.subcommand(App::new(CMD_VERSION)
|
||||||
|
.about("Print version information")
|
||||||
|
)
|
||||||
.subcommand(App::new(CMD_CHECK)
|
.subcommand(App::new(CMD_CHECK)
|
||||||
.about("Build a binary from the given .roc file, but don't run it")
|
.about("When developing, it's recommended to run `check` before `build`. It may provide a useful error message in cases where `build` panics")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(FLAG_TIME)
|
Arg::new(FLAG_TIME)
|
||||||
.long(FLAG_TIME)
|
.long(FLAG_TIME)
|
||||||
|
@ -190,7 +194,9 @@ pub fn build_app<'a>() -> App<'a> {
|
||||||
|
|
||||||
if cfg!(feature = "editor") {
|
if cfg!(feature = "editor") {
|
||||||
app.subcommand(
|
app.subcommand(
|
||||||
App::new(CMD_EDIT).about("Launch the Roc editor").arg(
|
App::new(CMD_EDIT)
|
||||||
|
.about("Launch the Roc editor (Work In Progress)")
|
||||||
|
.arg(
|
||||||
Arg::new(DIRECTORY_OR_FILES)
|
Arg::new(DIRECTORY_OR_FILES)
|
||||||
.index(1)
|
.index(1)
|
||||||
.multiple_values(true)
|
.multiple_values(true)
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
use roc_cli::build::check_file;
|
use roc_cli::build::check_file;
|
||||||
use roc_cli::{
|
use roc_cli::{
|
||||||
build_app, docs, repl, BuildConfig, CMD_BUILD, CMD_CHECK, CMD_DOCS, CMD_EDIT, CMD_REPL,
|
build_app, docs, repl, BuildConfig, CMD_BUILD, CMD_CHECK, CMD_DOCS, CMD_EDIT, CMD_REPL,
|
||||||
DIRECTORY_OR_FILES, FLAG_TIME, ROC_FILE,
|
CMD_VERSION, DIRECTORY_OR_FILES, FLAG_TIME, ROC_FILE,
|
||||||
};
|
};
|
||||||
use roc_load::file::LoadingProblem;
|
use roc_load::file::LoadingProblem;
|
||||||
use std::fs::{self, FileType};
|
use std::fs::{self, FileType};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate const_format;
|
||||||
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
||||||
|
|
||||||
|
@ -122,6 +125,11 @@ fn main() -> io::Result<()> {
|
||||||
|
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
Some(CMD_VERSION) => {
|
||||||
|
println!("roc {}", concatcp!(include_str!("../../version.txt"), "\n"));
|
||||||
|
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
|
|
@ -7,19 +7,6 @@ extern crate indoc;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod repl_eval {
|
mod repl_eval {
|
||||||
use cli_utils::helpers;
|
use cli_utils::helpers;
|
||||||
use roc_gen_llvm::run_roc::RocCallResult;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn check_discriminant_size() {
|
|
||||||
// tells us if the size of the discriminant has changed. Lots of other code
|
|
||||||
// relies on this size
|
|
||||||
let value: i64 = 1234;
|
|
||||||
assert_eq!(
|
|
||||||
std::mem::size_of_val(&RocCallResult::Success(value)),
|
|
||||||
roc_gen_llvm::run_roc::ROC_CALL_RESULT_DISCRIMINANT_SIZE
|
|
||||||
+ std::mem::size_of_val(&value)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const ERROR_MESSAGE_START: char = '─';
|
const ERROR_MESSAGE_START: char = '─';
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,6 @@ roc_gen_wasm = { path = "../gen_wasm", optional = true }
|
||||||
roc_gen_dev = { path = "../gen_dev", default-features = false }
|
roc_gen_dev = { path = "../gen_dev", default-features = false }
|
||||||
roc_reporting = { path = "../reporting" }
|
roc_reporting = { path = "../reporting" }
|
||||||
roc_std = { path = "../../roc_std" }
|
roc_std = { path = "../../roc_std" }
|
||||||
im = "15.0.0"
|
|
||||||
im-rc = "15.0.0"
|
|
||||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
libloading = "0.7.1"
|
libloading = "0.7.1"
|
||||||
tempfile = "3.2.0"
|
tempfile = "3.2.0"
|
||||||
|
|
|
@ -992,6 +992,22 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
||||||
Box::new(list_type(flex(TVAR1))),
|
Box::new(list_type(flex(TVAR1))),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// sublist : List elem, { start : Nat, len : Nat } -> List elem
|
||||||
|
add_top_level_function_type!(
|
||||||
|
Symbol::LIST_SUBLIST,
|
||||||
|
vec![
|
||||||
|
list_type(flex(TVAR1)),
|
||||||
|
SolvedType::Record {
|
||||||
|
fields: vec![
|
||||||
|
("start".into(), RecordField::Required(nat_type())),
|
||||||
|
("len".into(), RecordField::Required(nat_type())),
|
||||||
|
],
|
||||||
|
ext: Box::new(SolvedType::EmptyRecord),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
Box::new(list_type(flex(TVAR1))),
|
||||||
|
);
|
||||||
|
|
||||||
// drop : List elem, Nat -> List elem
|
// drop : List elem, Nat -> List elem
|
||||||
add_top_level_function_type!(
|
add_top_level_function_type!(
|
||||||
Symbol::LIST_DROP,
|
Symbol::LIST_DROP,
|
||||||
|
|
|
@ -14,8 +14,6 @@ roc_problem = { path = "../problem" }
|
||||||
roc_types = { path = "../types" }
|
roc_types = { path = "../types" }
|
||||||
roc_builtins = { path = "../builtins" }
|
roc_builtins = { path = "../builtins" }
|
||||||
ven_graph = { path = "../../vendor/pathfinding" }
|
ven_graph = { path = "../../vendor/pathfinding" }
|
||||||
im = "15.0.0"
|
|
||||||
im-rc = "15.0.0"
|
|
||||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -94,6 +94,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
||||||
LIST_MAP4 => list_map4,
|
LIST_MAP4 => list_map4,
|
||||||
LIST_TAKE_FIRST => list_take_first,
|
LIST_TAKE_FIRST => list_take_first,
|
||||||
LIST_TAKE_LAST => list_take_last,
|
LIST_TAKE_LAST => list_take_last,
|
||||||
|
LIST_SUBLIST => list_sublist,
|
||||||
LIST_DROP => list_drop,
|
LIST_DROP => list_drop,
|
||||||
LIST_DROP_AT => list_drop_at,
|
LIST_DROP_AT => list_drop_at,
|
||||||
LIST_DROP_FIRST => list_drop_first,
|
LIST_DROP_FIRST => list_drop_first,
|
||||||
|
@ -2060,6 +2061,54 @@ fn list_take_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// List.sublist : List elem, { start : Nat, len : Nat } -> List elem
|
||||||
|
fn list_sublist(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
let list_var = var_store.fresh();
|
||||||
|
let rec_var = var_store.fresh();
|
||||||
|
|
||||||
|
let sym_list = Symbol::ARG_1;
|
||||||
|
let sym_rec = Symbol::ARG_2;
|
||||||
|
|
||||||
|
let start_var = var_store.fresh();
|
||||||
|
let len_var = var_store.fresh();
|
||||||
|
|
||||||
|
let get_start = Access {
|
||||||
|
record_var: rec_var,
|
||||||
|
ext_var: var_store.fresh(),
|
||||||
|
field_var: var_store.fresh(),
|
||||||
|
loc_expr: Box::new(no_region(Var(sym_rec))),
|
||||||
|
field: "start".into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let get_len = Access {
|
||||||
|
record_var: rec_var,
|
||||||
|
ext_var: var_store.fresh(),
|
||||||
|
field_var: var_store.fresh(),
|
||||||
|
loc_expr: Box::new(no_region(Var(sym_rec))),
|
||||||
|
field: "len".into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let body_drop = RunLowLevel {
|
||||||
|
op: LowLevel::ListDrop,
|
||||||
|
args: vec![(list_var, Var(sym_list)), (start_var, get_start)],
|
||||||
|
ret_var: list_var,
|
||||||
|
};
|
||||||
|
|
||||||
|
let body_take = RunLowLevel {
|
||||||
|
op: LowLevel::ListTakeFirst,
|
||||||
|
args: vec![(list_var, body_drop), (len_var, get_len)],
|
||||||
|
ret_var: list_var,
|
||||||
|
};
|
||||||
|
|
||||||
|
defn(
|
||||||
|
symbol,
|
||||||
|
vec![(list_var, sym_list), (rec_var, sym_rec)],
|
||||||
|
var_store,
|
||||||
|
body_take,
|
||||||
|
list_var,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// List.drop : List elem, Nat -> List elem
|
/// List.drop : List elem, Nat -> List elem
|
||||||
fn list_drop(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn list_drop(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let list_var = var_store.fresh();
|
let list_var = var_store.fresh();
|
||||||
|
|
|
@ -872,7 +872,7 @@ fn canonicalize_pending_def<'a>(
|
||||||
// TODO try to remove this .clone()!
|
// TODO try to remove this .clone()!
|
||||||
value: loc_can_expr.value.clone(),
|
value: loc_can_expr.value.clone(),
|
||||||
},
|
},
|
||||||
pattern_vars: im::HashMap::clone(&vars_by_symbol),
|
pattern_vars: vars_by_symbol.clone(),
|
||||||
annotation: Some(Annotation {
|
annotation: Some(Annotation {
|
||||||
signature: typ.clone(),
|
signature: typ.clone(),
|
||||||
introduced_variables: output.introduced_variables.clone(),
|
introduced_variables: output.introduced_variables.clone(),
|
||||||
|
@ -1093,7 +1093,7 @@ fn canonicalize_pending_def<'a>(
|
||||||
// TODO try to remove this .clone()!
|
// TODO try to remove this .clone()!
|
||||||
value: loc_can_expr.value.clone(),
|
value: loc_can_expr.value.clone(),
|
||||||
},
|
},
|
||||||
pattern_vars: im::HashMap::clone(&vars_by_symbol),
|
pattern_vars: vars_by_symbol.clone(),
|
||||||
annotation: Some(Annotation {
|
annotation: Some(Annotation {
|
||||||
signature: typ.clone(),
|
signature: typ.clone(),
|
||||||
introduced_variables: output.introduced_variables.clone(),
|
introduced_variables: output.introduced_variables.clone(),
|
||||||
|
@ -1231,7 +1231,7 @@ fn canonicalize_pending_def<'a>(
|
||||||
region: loc_can_expr.region,
|
region: loc_can_expr.region,
|
||||||
value: loc_can_expr.value.clone(),
|
value: loc_can_expr.value.clone(),
|
||||||
},
|
},
|
||||||
pattern_vars: im::HashMap::clone(&vars_by_symbol),
|
pattern_vars: vars_by_symbol.clone(),
|
||||||
annotation: None,
|
annotation: None,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -952,7 +952,7 @@ pub fn local_successors<'a>(
|
||||||
references: &'a References,
|
references: &'a References,
|
||||||
closures: &'a MutMap<Symbol, References>,
|
closures: &'a MutMap<Symbol, References>,
|
||||||
) -> ImSet<Symbol> {
|
) -> ImSet<Symbol> {
|
||||||
let mut answer = im_rc::hashset::HashSet::clone(&references.lookups);
|
let mut answer = references.lookups.clone();
|
||||||
|
|
||||||
for call_symbol in references.calls.iter() {
|
for call_symbol in references.calls.iter() {
|
||||||
answer = answer.union(call_successors(*call_symbol, closures));
|
answer = answer.union(call_successors(*call_symbol, closures));
|
||||||
|
@ -962,7 +962,7 @@ pub fn local_successors<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_successors(call_symbol: Symbol, closures: &MutMap<Symbol, References>) -> ImSet<Symbol> {
|
fn call_successors(call_symbol: Symbol, closures: &MutMap<Symbol, References>) -> ImSet<Symbol> {
|
||||||
let mut answer = im_rc::hashset::HashSet::default();
|
let mut answer = ImSet::default();
|
||||||
let mut seen = MutSet::default();
|
let mut seen = MutSet::default();
|
||||||
let mut queue = vec![call_symbol];
|
let mut queue = vec![call_symbol];
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,6 @@ roc_collections = { path = "../collections" }
|
||||||
roc_region = { path = "../region" }
|
roc_region = { path = "../region" }
|
||||||
roc_module = { path = "../module" }
|
roc_module = { path = "../module" }
|
||||||
roc_parse = { path = "../parse" }
|
roc_parse = { path = "../parse" }
|
||||||
im = "15.0.0"
|
|
||||||
im-rc = "15.0.0"
|
|
||||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -16,8 +16,6 @@ roc_builtins = { path = "../builtins" }
|
||||||
roc_unify = { path = "../unify" }
|
roc_unify = { path = "../unify" }
|
||||||
roc_solve = { path = "../solve" }
|
roc_solve = { path = "../solve" }
|
||||||
roc_mono = { path = "../mono" }
|
roc_mono = { path = "../mono" }
|
||||||
im = "15.0.0"
|
|
||||||
im-rc = "15.0.0"
|
|
||||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
target-lexicon = "0.12.2"
|
target-lexicon = "0.12.2"
|
||||||
# TODO: Deal with the update of object to 0.27.
|
# TODO: Deal with the update of object to 0.27.
|
||||||
|
|
|
@ -8,23 +8,11 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
roc_collections = { path = "../collections" }
|
roc_collections = { path = "../collections" }
|
||||||
roc_region = { path = "../region" }
|
|
||||||
roc_module = { path = "../module" }
|
roc_module = { path = "../module" }
|
||||||
roc_problem = { path = "../problem" }
|
|
||||||
roc_types = { path = "../types" }
|
|
||||||
roc_builtins = { path = "../builtins" }
|
roc_builtins = { path = "../builtins" }
|
||||||
roc_unify = { path = "../unify" }
|
|
||||||
roc_solve = { path = "../solve" }
|
|
||||||
roc_mono = { path = "../mono" }
|
roc_mono = { path = "../mono" }
|
||||||
roc_std = { path = "../../roc_std" }
|
roc_std = { path = "../../roc_std" }
|
||||||
morphic_lib = { path = "../../vendor/morphic_lib" }
|
morphic_lib = { path = "../../vendor/morphic_lib" }
|
||||||
im = "15.0.0"
|
|
||||||
im-rc = "15.0.0"
|
|
||||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
inkwell = { path = "../../vendor/inkwell" }
|
inkwell = { path = "../../vendor/inkwell" }
|
||||||
target-lexicon = "0.12.2"
|
target-lexicon = "0.12.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
roc_can = { path = "../can" }
|
|
||||||
roc_parse = { path = "../parse" }
|
|
||||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
|
||||||
|
|
|
@ -3351,8 +3351,7 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
builder.position_at_end(entry);
|
builder.position_at_end(entry);
|
||||||
|
|
||||||
let elements = [Layout::Builtin(Builtin::Int64), return_layout];
|
let wrapped_layout = roc_result_layout(env.arena, return_layout);
|
||||||
let wrapped_layout = Layout::Struct(&elements);
|
|
||||||
call_roc_function(env, roc_function, &wrapped_layout, arguments_for_call)
|
call_roc_function(env, roc_function, &wrapped_layout, arguments_for_call)
|
||||||
} else {
|
} else {
|
||||||
call_roc_function(env, roc_function, &return_layout, arguments_for_call)
|
call_roc_function(env, roc_function, &return_layout, arguments_for_call)
|
||||||
|
@ -3380,18 +3379,11 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>(
|
||||||
return_layout: Layout<'a>,
|
return_layout: Layout<'a>,
|
||||||
c_function_name: &str,
|
c_function_name: &str,
|
||||||
) -> FunctionValue<'ctx> {
|
) -> FunctionValue<'ctx> {
|
||||||
let context = env.context;
|
|
||||||
|
|
||||||
// a tagged union to indicate to the test loader that a panic occurred.
|
// a tagged union to indicate to the test loader that a panic occurred.
|
||||||
// especially when running 32-bit binaries on a 64-bit machine, there
|
// especially when running 32-bit binaries on a 64-bit machine, there
|
||||||
// does not seem to be a smarter solution
|
// does not seem to be a smarter solution
|
||||||
let wrapper_return_type = context.struct_type(
|
let wrapper_return_type =
|
||||||
&[
|
roc_result_type(env, roc_function.get_type().get_return_type().unwrap());
|
||||||
context.i64_type().into(),
|
|
||||||
basic_type_from_layout(env, &return_layout),
|
|
||||||
],
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut cc_argument_types = Vec::with_capacity_in(arguments.len(), env.arena);
|
let mut cc_argument_types = Vec::with_capacity_in(arguments.len(), env.arena);
|
||||||
for layout in arguments {
|
for layout in arguments {
|
||||||
|
@ -3510,8 +3502,6 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
|
||||||
return_layout: Layout<'a>,
|
return_layout: Layout<'a>,
|
||||||
c_function_name: &str,
|
c_function_name: &str,
|
||||||
) -> FunctionValue<'ctx> {
|
) -> FunctionValue<'ctx> {
|
||||||
let context = env.context;
|
|
||||||
|
|
||||||
if env.is_gen_test {
|
if env.is_gen_test {
|
||||||
return expose_function_to_host_help_c_abi_gen_test(
|
return expose_function_to_host_help_c_abi_gen_test(
|
||||||
env,
|
env,
|
||||||
|
@ -3533,15 +3523,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
|
||||||
);
|
);
|
||||||
|
|
||||||
let wrapper_return_type = if env.is_gen_test {
|
let wrapper_return_type = if env.is_gen_test {
|
||||||
context
|
roc_result_type(env, roc_function.get_type().get_return_type().unwrap()).into()
|
||||||
.struct_type(
|
|
||||||
&[
|
|
||||||
context.i64_type().into(),
|
|
||||||
roc_function.get_type().get_return_type().unwrap(),
|
|
||||||
],
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
} else {
|
} else {
|
||||||
// roc_function.get_type().get_return_type().unwrap()
|
// roc_function.get_type().get_return_type().unwrap()
|
||||||
basic_type_from_layout(env, &return_layout)
|
basic_type_from_layout(env, &return_layout)
|
||||||
|
@ -3708,12 +3690,7 @@ fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>(
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
|
|
||||||
let return_type = basic_type_from_layout(env, &return_layout);
|
let return_type = basic_type_from_layout(env, &return_layout);
|
||||||
|
let call_result_type = roc_result_type(env, return_type.as_basic_type_enum());
|
||||||
let call_result_type = context.struct_type(
|
|
||||||
&[context.i64_type().into(), return_type.as_basic_type_enum()],
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
let result_alloca = builder.build_alloca(call_result_type, "result");
|
let result_alloca = builder.build_alloca(call_result_type, "result");
|
||||||
|
|
||||||
let then_block = context.append_basic_block(parent, "then_block");
|
let then_block = context.append_basic_block(parent, "then_block");
|
||||||
|
@ -3811,12 +3788,8 @@ fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>(
|
||||||
ptr_int
|
ptr_int
|
||||||
};
|
};
|
||||||
|
|
||||||
let u8_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic);
|
|
||||||
let return_type = context.struct_type(&[context.i64_type().into(), u8_ptr.into()], false);
|
|
||||||
// let return_type = call_result_type;
|
|
||||||
|
|
||||||
let return_value = {
|
let return_value = {
|
||||||
let v1 = return_type.const_zero();
|
let v1 = call_result_type.const_zero();
|
||||||
|
|
||||||
// flag is non-zero, indicating failure
|
// flag is non-zero, indicating failure
|
||||||
let flag = context.i64_type().const_int(1, false);
|
let flag = context.i64_type().const_int(1, false);
|
||||||
|
@ -3831,17 +3804,7 @@ fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>(
|
||||||
v3
|
v3
|
||||||
};
|
};
|
||||||
|
|
||||||
// bitcast result alloca so we can store our concrete type { flag, error_msg } in there
|
builder.build_store(result_alloca, return_value);
|
||||||
let result_alloca_bitcast = builder
|
|
||||||
.build_bitcast(
|
|
||||||
result_alloca,
|
|
||||||
return_type.ptr_type(AddressSpace::Generic),
|
|
||||||
"result_alloca_bitcast",
|
|
||||||
)
|
|
||||||
.into_pointer_value();
|
|
||||||
|
|
||||||
// store our return value
|
|
||||||
builder.build_store(result_alloca_bitcast, return_value);
|
|
||||||
|
|
||||||
env.builder.build_unconditional_branch(cont_block);
|
env.builder.build_unconditional_branch(cont_block);
|
||||||
}
|
}
|
||||||
|
@ -3866,6 +3829,30 @@ fn make_exception_catcher<'a, 'ctx, 'env>(
|
||||||
function_value
|
function_value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn roc_result_layout<'a>(arena: &'a Bump, return_layout: Layout<'a>) -> Layout<'a> {
|
||||||
|
let elements = [
|
||||||
|
Layout::Builtin(Builtin::Int64),
|
||||||
|
Layout::Builtin(Builtin::Usize),
|
||||||
|
return_layout,
|
||||||
|
];
|
||||||
|
|
||||||
|
Layout::Struct(arena.alloc(elements))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn roc_result_type<'a, 'ctx, 'env>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
return_type: BasicTypeEnum<'ctx>,
|
||||||
|
) -> StructType<'ctx> {
|
||||||
|
env.context.struct_type(
|
||||||
|
&[
|
||||||
|
env.context.i64_type().into(),
|
||||||
|
env.context.i8_type().ptr_type(AddressSpace::Generic).into(),
|
||||||
|
return_type,
|
||||||
|
],
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn make_good_roc_result<'a, 'ctx, 'env>(
|
fn make_good_roc_result<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
return_layout: Layout<'a>,
|
return_layout: Layout<'a>,
|
||||||
|
@ -3874,11 +3861,7 @@ fn make_good_roc_result<'a, 'ctx, 'env>(
|
||||||
let context = env.context;
|
let context = env.context;
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
|
|
||||||
let content_type = basic_type_from_layout(env, &return_layout);
|
let v1 = roc_result_type(env, return_value.get_type()).const_zero();
|
||||||
let wrapper_return_type =
|
|
||||||
context.struct_type(&[context.i64_type().into(), content_type], false);
|
|
||||||
|
|
||||||
let v1 = wrapper_return_type.const_zero();
|
|
||||||
|
|
||||||
let v2 = builder
|
let v2 = builder
|
||||||
.build_insert_value(v1, context.i64_type().const_zero(), 0, "set_no_error")
|
.build_insert_value(v1, context.i64_type().const_zero(), 0, "set_no_error")
|
||||||
|
@ -3890,11 +3873,11 @@ fn make_good_roc_result<'a, 'ctx, 'env>(
|
||||||
"load_call_result_passed_by_ptr",
|
"load_call_result_passed_by_ptr",
|
||||||
);
|
);
|
||||||
builder
|
builder
|
||||||
.build_insert_value(v2, loaded, 1, "set_call_result")
|
.build_insert_value(v2, loaded, 2, "set_call_result")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
} else {
|
} else {
|
||||||
builder
|
builder
|
||||||
.build_insert_value(v2, return_value, 1, "set_call_result")
|
.build_insert_value(v2, return_value, 2, "set_call_result")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3923,13 +3906,8 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let wrapper_return_type = context.struct_type(
|
let wrapper_return_type =
|
||||||
&[
|
roc_result_type(env, roc_function.get_type().get_return_type().unwrap());
|
||||||
context.i64_type().into(),
|
|
||||||
basic_type_from_layout(env, &return_layout),
|
|
||||||
],
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
// argument_types.push(wrapper_return_type.ptr_type(AddressSpace::Generic).into());
|
// argument_types.push(wrapper_return_type.ptr_type(AddressSpace::Generic).into());
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
use RocCallResult::*;
|
|
||||||
|
|
||||||
/// This must have the same size as the repr() of RocCallResult!
|
/// This must have the same size as the repr() of RocCallResult!
|
||||||
pub const ROC_CALL_RESULT_DISCRIMINANT_SIZE: usize = std::mem::size_of::<u64>();
|
pub const ROC_CALL_RESULT_DISCRIMINANT_SIZE: usize = std::mem::size_of::<u64>();
|
||||||
|
|
||||||
#[repr(u64)]
|
#[repr(C)]
|
||||||
pub enum RocCallResult<T> {
|
pub struct RocCallResult<T> {
|
||||||
Success(T),
|
tag: u64,
|
||||||
Failure(*mut c_char),
|
error_msg: *mut c_char,
|
||||||
|
value: MaybeUninit<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Sized> From<RocCallResult<T>> for Result<T, String> {
|
impl<T: Sized> From<RocCallResult<T>> for Result<T, String> {
|
||||||
fn from(call_result: RocCallResult<T>) -> Self {
|
fn from(call_result: RocCallResult<T>) -> Self {
|
||||||
match call_result {
|
match call_result.tag {
|
||||||
Success(value) => Ok(value),
|
0 => Ok(unsafe { call_result.value.assume_init() }),
|
||||||
Failure(failure) => Err({
|
_ => Err({
|
||||||
let raw = unsafe { CString::from_raw(failure) };
|
let raw = unsafe { CString::from_raw(call_result.error_msg) };
|
||||||
|
|
||||||
let result = format!("{:?}", raw);
|
let result = format!("{:?}", raw);
|
||||||
|
|
||||||
|
@ -86,7 +87,7 @@ macro_rules! run_jit_function_dynamic_type {
|
||||||
.ok_or(format!("Unable to JIT compile `{}`", $main_fn_name))
|
.ok_or(format!("Unable to JIT compile `{}`", $main_fn_name))
|
||||||
.expect("errored");
|
.expect("errored");
|
||||||
|
|
||||||
let size = roc_gen_llvm::run_roc::ROC_CALL_RESULT_DISCRIMINANT_SIZE + $bytes;
|
let size = std::mem::size_of::<RocCallResult<()>>() + $bytes;
|
||||||
let layout = std::alloc::Layout::array::<u8>(size).unwrap();
|
let layout = std::alloc::Layout::array::<u8>(size).unwrap();
|
||||||
let result = std::alloc::alloc(layout);
|
let result = std::alloc::alloc(layout);
|
||||||
main(result);
|
main(result);
|
||||||
|
@ -94,7 +95,7 @@ macro_rules! run_jit_function_dynamic_type {
|
||||||
let flag = *result;
|
let flag = *result;
|
||||||
|
|
||||||
if flag == 0 {
|
if flag == 0 {
|
||||||
$transform(result.offset(8) as *const u8)
|
$transform(result.add(std::mem::size_of::<RocCallResult<()>>()) as *const u8)
|
||||||
} else {
|
} else {
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
use bumpalo::{self, collections::Vec};
|
use bumpalo::{self, collections::Vec};
|
||||||
|
|
||||||
use code_builder::Align;
|
use code_builder::Align;
|
||||||
use roc_builtins::bitcode::{self, FloatWidth};
|
|
||||||
use roc_collections::all::MutMap;
|
use roc_collections::all::MutMap;
|
||||||
use roc_module::low_level::LowLevel;
|
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_mono::ir::{CallType, Expr, JoinPointId, Literal, Proc, Stmt};
|
use roc_mono::ir::{CallType, Expr, JoinPointId, Literal, Proc, Stmt};
|
||||||
use roc_mono::layout::{Layout, LayoutIds};
|
use roc_mono::layout::{Layout, LayoutIds};
|
||||||
|
|
||||||
use crate::layout::WasmLayout;
|
use crate::layout::WasmLayout;
|
||||||
|
use crate::low_level::{build_call_low_level, LowlevelBuildResult};
|
||||||
use crate::storage::{Storage, StoredValue, StoredValueKind};
|
use crate::storage::{Storage, StoredValue, StoredValueKind};
|
||||||
use crate::wasm_module::linking::{
|
use crate::wasm_module::linking::{
|
||||||
DataSymbol, LinkingSection, RelocationSection, WasmObjectSymbol, WASM_SYM_BINDING_WEAK,
|
DataSymbol, LinkingSection, RelocationSection, WasmObjectSymbol, WASM_SYM_BINDING_WEAK,
|
||||||
|
@ -24,7 +23,7 @@ use crate::wasm_module::{
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
copy_memory, CopyMemoryConfig, Env, BUILTINS_IMPORT_MODULE_NAME, MEMORY_NAME, PTR_TYPE,
|
copy_memory, CopyMemoryConfig, Env, BUILTINS_IMPORT_MODULE_NAME, MEMORY_NAME, PTR_TYPE,
|
||||||
STACK_POINTER_NAME,
|
STACK_POINTER_GLOBAL_ID, STACK_POINTER_NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The memory address where the constants data will be loaded during module instantiation.
|
/// The memory address where the constants data will be loaded during module instantiation.
|
||||||
|
@ -84,12 +83,12 @@ impl<'a> WasmBackend<'a> {
|
||||||
exports.push(Export {
|
exports.push(Export {
|
||||||
name: STACK_POINTER_NAME.to_string(),
|
name: STACK_POINTER_NAME.to_string(),
|
||||||
ty: ExportType::Global,
|
ty: ExportType::Global,
|
||||||
index: 0,
|
index: STACK_POINTER_GLOBAL_ID,
|
||||||
});
|
});
|
||||||
|
|
||||||
linker_symbols.push(SymInfo::Global(WasmObjectSymbol::Defined {
|
linker_symbols.push(SymInfo::Global(WasmObjectSymbol::Defined {
|
||||||
flags: WASM_SYM_BINDING_WEAK,
|
flags: WASM_SYM_BINDING_WEAK, // TODO: this works but means external .o files decide how much stack we have!
|
||||||
index: 0,
|
index: STACK_POINTER_GLOBAL_ID,
|
||||||
name: STACK_POINTER_NAME.to_string(),
|
name: STACK_POINTER_NAME.to_string(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -487,7 +486,29 @@ impl<'a> WasmBackend<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
CallType::LowLevel { op: lowlevel, .. } => {
|
CallType::LowLevel { op: lowlevel, .. } => {
|
||||||
self.build_call_low_level(lowlevel, arguments, layout)
|
let return_layout = WasmLayout::new(layout);
|
||||||
|
self.storage.load_symbols(&mut self.code_builder, arguments);
|
||||||
|
|
||||||
|
let build_result = build_call_low_level(
|
||||||
|
&mut self.code_builder,
|
||||||
|
&mut self.storage,
|
||||||
|
lowlevel,
|
||||||
|
arguments,
|
||||||
|
&return_layout,
|
||||||
|
);
|
||||||
|
use LowlevelBuildResult::*;
|
||||||
|
|
||||||
|
match build_result {
|
||||||
|
Done => Ok(()),
|
||||||
|
BuiltinCall(name) => {
|
||||||
|
self.call_imported_builtin(name, arguments, &return_layout);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
NotImplemented => Err(format!(
|
||||||
|
"Low level operation {:?} is not yet implemented",
|
||||||
|
lowlevel
|
||||||
|
)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
x => Err(format!("the call type, {:?}, is not yet implemented", x)),
|
x => Err(format!("the call type, {:?}, is not yet implemented", x)),
|
||||||
},
|
},
|
||||||
|
@ -665,90 +686,11 @@ impl<'a> WasmBackend<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_call_low_level(
|
|
||||||
&mut self,
|
|
||||||
lowlevel: &LowLevel,
|
|
||||||
args: &'a [Symbol],
|
|
||||||
return_layout: &Layout<'a>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
self.storage.load_symbols(&mut self.code_builder, args);
|
|
||||||
let wasm_layout = WasmLayout::new(return_layout);
|
|
||||||
let ret_type = wasm_layout.value_type();
|
|
||||||
|
|
||||||
let panic_ret_type = || panic!("Invalid return type for {:?}: {:?}", lowlevel, ret_type);
|
|
||||||
|
|
||||||
match lowlevel {
|
|
||||||
LowLevel::NumAdd => match ret_type {
|
|
||||||
ValueType::I32 => self.code_builder.i32_add(),
|
|
||||||
ValueType::I64 => self.code_builder.i64_add(),
|
|
||||||
ValueType::F32 => self.code_builder.f32_add(),
|
|
||||||
ValueType::F64 => self.code_builder.f64_add(),
|
|
||||||
},
|
|
||||||
LowLevel::NumSub => match ret_type {
|
|
||||||
ValueType::I32 => self.code_builder.i32_sub(),
|
|
||||||
ValueType::I64 => self.code_builder.i64_sub(),
|
|
||||||
ValueType::F32 => self.code_builder.f32_sub(),
|
|
||||||
ValueType::F64 => self.code_builder.f64_sub(),
|
|
||||||
},
|
|
||||||
LowLevel::NumMul => match ret_type {
|
|
||||||
ValueType::I32 => self.code_builder.i32_mul(),
|
|
||||||
ValueType::I64 => self.code_builder.i64_mul(),
|
|
||||||
ValueType::F32 => self.code_builder.f32_mul(),
|
|
||||||
ValueType::F64 => self.code_builder.f64_mul(),
|
|
||||||
},
|
|
||||||
LowLevel::NumGt => match self.get_uniform_arg_type(args) {
|
|
||||||
ValueType::I32 => self.code_builder.i32_gt_s(),
|
|
||||||
ValueType::I64 => self.code_builder.i64_gt_s(),
|
|
||||||
ValueType::F32 => self.code_builder.f32_gt(),
|
|
||||||
ValueType::F64 => self.code_builder.f64_gt(),
|
|
||||||
},
|
|
||||||
LowLevel::Eq => match self.get_uniform_arg_type(args) {
|
|
||||||
ValueType::I32 => self.code_builder.i32_eq(),
|
|
||||||
ValueType::I64 => self.code_builder.i64_eq(),
|
|
||||||
ValueType::F32 => self.code_builder.f32_eq(),
|
|
||||||
ValueType::F64 => self.code_builder.f64_eq(),
|
|
||||||
},
|
|
||||||
LowLevel::NumNeg => match ret_type {
|
|
||||||
ValueType::I32 => {
|
|
||||||
self.code_builder.i32_const(-1);
|
|
||||||
self.code_builder.i32_mul();
|
|
||||||
}
|
|
||||||
ValueType::I64 => {
|
|
||||||
self.code_builder.i64_const(-1);
|
|
||||||
self.code_builder.i64_mul();
|
|
||||||
}
|
|
||||||
ValueType::F32 => self.code_builder.f32_neg(),
|
|
||||||
ValueType::F64 => self.code_builder.f64_neg(),
|
|
||||||
},
|
|
||||||
LowLevel::NumAtan => {
|
|
||||||
let name = match ret_type {
|
|
||||||
ValueType::F32 => &bitcode::NUM_ATAN[FloatWidth::F32],
|
|
||||||
ValueType::F64 => &bitcode::NUM_ATAN[FloatWidth::F64],
|
|
||||||
_ => panic_ret_type(),
|
|
||||||
};
|
|
||||||
self.call_imported_builtin(name, &[ret_type], Some(ret_type));
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(format!("unsupported low-level op {:?}", lowlevel));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the ValueType for a set of arguments that are required to have the same type
|
|
||||||
fn get_uniform_arg_type(&self, args: &'a [Symbol]) -> ValueType {
|
|
||||||
let value_type = self.storage.get(&args[0]).value_type();
|
|
||||||
for arg in args.iter().skip(1) {
|
|
||||||
debug_assert!(self.storage.get(arg).value_type() == value_type);
|
|
||||||
}
|
|
||||||
value_type
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call_imported_builtin(
|
fn call_imported_builtin(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
arg_types: &[ValueType],
|
arguments: &[Symbol],
|
||||||
ret_type: Option<ValueType>,
|
ret_layout: &WasmLayout,
|
||||||
) {
|
) {
|
||||||
let (fn_index, linker_symbol_index) = match self.builtin_sym_index_map.get(name) {
|
let (fn_index, linker_symbol_index) = match self.builtin_sym_index_map.get(name) {
|
||||||
Some(sym_idx) => match &self.linker_symbols[*sym_idx] {
|
Some(sym_idx) => match &self.linker_symbols[*sym_idx] {
|
||||||
|
@ -759,11 +701,11 @@ impl<'a> WasmBackend<'a> {
|
||||||
},
|
},
|
||||||
|
|
||||||
None => {
|
None => {
|
||||||
let mut param_types = Vec::with_capacity_in(arg_types.len(), self.env.arena);
|
let mut param_types = Vec::with_capacity_in(arguments.len(), self.env.arena);
|
||||||
param_types.extend_from_slice(arg_types);
|
param_types.extend(arguments.iter().map(|a| self.storage.get(a).value_type()));
|
||||||
let signature_index = self.module.types.insert(Signature {
|
let signature_index = self.module.types.insert(Signature {
|
||||||
param_types,
|
param_types,
|
||||||
ret_type,
|
ret_type: Some(ret_layout.value_type()), // TODO: handle builtins with no return value
|
||||||
});
|
});
|
||||||
|
|
||||||
let import_index = self.module.import.entries.len() as u32;
|
let import_index = self.module.import.entries.len() as u32;
|
||||||
|
@ -787,8 +729,8 @@ impl<'a> WasmBackend<'a> {
|
||||||
self.code_builder.call(
|
self.code_builder.call(
|
||||||
fn_index,
|
fn_index,
|
||||||
linker_symbol_index,
|
linker_symbol_index,
|
||||||
arg_types.len(),
|
arguments.len(),
|
||||||
ret_type.is_some(),
|
true, // TODO: handle builtins with no return value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,14 @@ impl WasmLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
Self::Primitive(_, size) => *size,
|
||||||
|
Self::StackMemory { size, .. } => *size,
|
||||||
|
Self::HeapMemory => PTR_SIZE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_stack_memory(&self) -> bool {
|
pub fn is_stack_memory(&self) -> bool {
|
||||||
matches!(self, Self::StackMemory { .. })
|
matches!(self, Self::StackMemory { .. })
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
mod backend;
|
mod backend;
|
||||||
mod layout;
|
mod layout;
|
||||||
|
mod low_level;
|
||||||
mod storage;
|
mod storage;
|
||||||
pub mod wasm_module;
|
pub mod wasm_module;
|
||||||
|
|
||||||
|
@ -126,7 +127,15 @@ pub fn copy_memory(code_builder: &mut CodeBuilder, config: CopyMemoryConfig) {
|
||||||
|
|
||||||
/// Round up to alignment_bytes (which must be a power of 2)
|
/// Round up to alignment_bytes (which must be a power of 2)
|
||||||
pub fn round_up_to_alignment(unaligned: i32, alignment_bytes: i32) -> i32 {
|
pub fn round_up_to_alignment(unaligned: i32, alignment_bytes: i32) -> i32 {
|
||||||
debug_assert!(alignment_bytes.count_ones() == 1);
|
if alignment_bytes <= 1 {
|
||||||
|
return unaligned;
|
||||||
|
}
|
||||||
|
if alignment_bytes.count_ones() != 1 {
|
||||||
|
panic!(
|
||||||
|
"Cannot align to {} bytes. Not a power of 2.",
|
||||||
|
alignment_bytes
|
||||||
|
);
|
||||||
|
}
|
||||||
let mut aligned = unaligned;
|
let mut aligned = unaligned;
|
||||||
aligned += alignment_bytes - 1; // if lower bits are non-zero, push it over the next boundary
|
aligned += alignment_bytes - 1; // if lower bits are non-zero, push it over the next boundary
|
||||||
aligned &= -alignment_bytes; // mask with a flag that has upper bits 1, lower bits 0
|
aligned &= -alignment_bytes; // mask with a flag that has upper bits 1, lower bits 0
|
||||||
|
|
360
compiler/gen_wasm/src/low_level.rs
Normal file
360
compiler/gen_wasm/src/low_level.rs
Normal file
|
@ -0,0 +1,360 @@
|
||||||
|
use roc_builtins::bitcode::{self, FloatWidth};
|
||||||
|
use roc_module::low_level::{LowLevel, LowLevel::*};
|
||||||
|
use roc_module::symbol::Symbol;
|
||||||
|
|
||||||
|
use crate::layout::WasmLayout;
|
||||||
|
use crate::storage::Storage;
|
||||||
|
use crate::wasm_module::{
|
||||||
|
CodeBuilder,
|
||||||
|
ValueType::{self, *},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub enum LowlevelBuildResult {
|
||||||
|
Done,
|
||||||
|
BuiltinCall(&'static str),
|
||||||
|
NotImplemented,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_call_low_level<'a>(
|
||||||
|
code_builder: &mut CodeBuilder<'a>,
|
||||||
|
storage: &mut Storage<'a>,
|
||||||
|
lowlevel: &LowLevel,
|
||||||
|
args: &'a [Symbol],
|
||||||
|
ret_layout: &WasmLayout,
|
||||||
|
) -> LowlevelBuildResult {
|
||||||
|
use LowlevelBuildResult::*;
|
||||||
|
|
||||||
|
let panic_ret_type = || panic!("Invalid return layout for {:?}: {:?}", lowlevel, ret_layout);
|
||||||
|
|
||||||
|
match lowlevel {
|
||||||
|
StrConcat | StrJoinWith | StrIsEmpty | StrStartsWith | StrStartsWithCodePt
|
||||||
|
| StrEndsWith | StrSplit | StrCountGraphemes | StrFromInt | StrFromUtf8 | StrTrimLeft
|
||||||
|
| StrFromUtf8Range | StrToUtf8 | StrRepeat | StrFromFloat | StrTrim | ListLen
|
||||||
|
| ListGetUnsafe | ListSet | ListSingle | ListRepeat | ListReverse | ListConcat
|
||||||
|
| ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap | ListMap2
|
||||||
|
| ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk | ListWalkUntil
|
||||||
|
| ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith | ListTakeFirst
|
||||||
|
| ListTakeLast | ListDrop | ListDropAt | ListSwap | ListAny | ListFindUnsafe | DictSize
|
||||||
|
| DictEmpty | DictInsert | DictRemove | DictContains | DictGetUnsafe | DictKeys
|
||||||
|
| DictValues | DictUnion | DictIntersection | DictDifference | DictWalk | SetFromList => {
|
||||||
|
return NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
NumAdd => match ret_layout.value_type() {
|
||||||
|
I32 => code_builder.i32_add(),
|
||||||
|
I64 => code_builder.i64_add(),
|
||||||
|
F32 => code_builder.f32_add(),
|
||||||
|
F64 => code_builder.f64_add(),
|
||||||
|
},
|
||||||
|
NumAddWrap => match ret_layout.value_type() {
|
||||||
|
I32 => {
|
||||||
|
code_builder.i32_add();
|
||||||
|
wrap_i32(code_builder, ret_layout.size());
|
||||||
|
}
|
||||||
|
I64 => code_builder.i64_add(),
|
||||||
|
F32 => code_builder.f32_add(),
|
||||||
|
F64 => code_builder.f64_add(),
|
||||||
|
},
|
||||||
|
NumAddChecked => return NotImplemented,
|
||||||
|
NumSub => match ret_layout.value_type() {
|
||||||
|
I32 => code_builder.i32_sub(),
|
||||||
|
I64 => code_builder.i64_sub(),
|
||||||
|
F32 => code_builder.f32_sub(),
|
||||||
|
F64 => code_builder.f64_sub(),
|
||||||
|
},
|
||||||
|
NumSubWrap => match ret_layout.value_type() {
|
||||||
|
I32 => {
|
||||||
|
code_builder.i32_sub();
|
||||||
|
wrap_i32(code_builder, ret_layout.size());
|
||||||
|
}
|
||||||
|
I64 => code_builder.i64_sub(),
|
||||||
|
F32 => code_builder.f32_sub(),
|
||||||
|
F64 => code_builder.f64_sub(),
|
||||||
|
},
|
||||||
|
NumSubChecked => return NotImplemented,
|
||||||
|
NumMul => match ret_layout.value_type() {
|
||||||
|
I32 => code_builder.i32_mul(),
|
||||||
|
I64 => code_builder.i64_mul(),
|
||||||
|
F32 => code_builder.f32_mul(),
|
||||||
|
F64 => code_builder.f64_mul(),
|
||||||
|
},
|
||||||
|
NumMulWrap => match ret_layout.value_type() {
|
||||||
|
I32 => {
|
||||||
|
code_builder.i32_mul();
|
||||||
|
wrap_i32(code_builder, ret_layout.size());
|
||||||
|
}
|
||||||
|
I64 => code_builder.i64_mul(),
|
||||||
|
F32 => code_builder.f32_mul(),
|
||||||
|
F64 => code_builder.f64_mul(),
|
||||||
|
},
|
||||||
|
NumMulChecked => return NotImplemented,
|
||||||
|
NumGt => match storage.get(&args[0]).value_type() {
|
||||||
|
I32 => code_builder.i32_gt_s(),
|
||||||
|
I64 => code_builder.i64_gt_s(),
|
||||||
|
F32 => code_builder.f32_gt(),
|
||||||
|
F64 => code_builder.f64_gt(),
|
||||||
|
},
|
||||||
|
NumGte => match storage.get(&args[0]).value_type() {
|
||||||
|
I32 => code_builder.i32_ge_s(),
|
||||||
|
I64 => code_builder.i64_ge_s(),
|
||||||
|
F32 => code_builder.f32_ge(),
|
||||||
|
F64 => code_builder.f64_ge(),
|
||||||
|
},
|
||||||
|
NumLt => match storage.get(&args[0]).value_type() {
|
||||||
|
I32 => code_builder.i32_lt_s(),
|
||||||
|
I64 => code_builder.i64_lt_s(),
|
||||||
|
F32 => code_builder.f32_lt(),
|
||||||
|
F64 => code_builder.f64_lt(),
|
||||||
|
},
|
||||||
|
NumLte => match storage.get(&args[0]).value_type() {
|
||||||
|
I32 => code_builder.i32_le_s(),
|
||||||
|
I64 => code_builder.i64_le_s(),
|
||||||
|
F32 => code_builder.f32_le(),
|
||||||
|
F64 => code_builder.f64_le(),
|
||||||
|
},
|
||||||
|
NumCompare => return NotImplemented,
|
||||||
|
NumDivUnchecked => match ret_layout.value_type() {
|
||||||
|
I32 => code_builder.i32_div_s(),
|
||||||
|
I64 => code_builder.i64_div_s(),
|
||||||
|
F32 => code_builder.f32_div(),
|
||||||
|
F64 => code_builder.f64_div(),
|
||||||
|
},
|
||||||
|
NumDivCeilUnchecked => return NotImplemented,
|
||||||
|
NumRemUnchecked => match ret_layout.value_type() {
|
||||||
|
I32 => code_builder.i32_rem_s(),
|
||||||
|
I64 => code_builder.i64_rem_s(),
|
||||||
|
F32 => return NotImplemented,
|
||||||
|
F64 => return NotImplemented,
|
||||||
|
},
|
||||||
|
NumIsMultipleOf => return NotImplemented,
|
||||||
|
NumAbs => match ret_layout.value_type() {
|
||||||
|
I32 => {
|
||||||
|
code_builder.i32_const(0);
|
||||||
|
storage.load_symbols(code_builder, args);
|
||||||
|
code_builder.i32_sub();
|
||||||
|
storage.load_symbols(code_builder, args);
|
||||||
|
code_builder.i32_const(0);
|
||||||
|
code_builder.i32_ge_s();
|
||||||
|
code_builder.select();
|
||||||
|
}
|
||||||
|
I64 => {
|
||||||
|
code_builder.i64_const(0);
|
||||||
|
storage.load_symbols(code_builder, args);
|
||||||
|
code_builder.i64_sub();
|
||||||
|
storage.load_symbols(code_builder, args);
|
||||||
|
code_builder.i64_const(0);
|
||||||
|
code_builder.i64_ge_s();
|
||||||
|
code_builder.select();
|
||||||
|
}
|
||||||
|
F32 => code_builder.f32_abs(),
|
||||||
|
F64 => code_builder.f64_abs(),
|
||||||
|
},
|
||||||
|
NumNeg => {
|
||||||
|
match ret_layout.value_type() {
|
||||||
|
I32 => {
|
||||||
|
// Unfortunate local.set/local.get
|
||||||
|
code_builder.i32_const(0);
|
||||||
|
storage.load_symbols(code_builder, args);
|
||||||
|
code_builder.i32_sub();
|
||||||
|
}
|
||||||
|
I64 => {
|
||||||
|
// Unfortunate local.set/local.get
|
||||||
|
code_builder.i64_const(0);
|
||||||
|
storage.load_symbols(code_builder, args);
|
||||||
|
code_builder.i64_sub();
|
||||||
|
}
|
||||||
|
F32 => code_builder.f32_neg(),
|
||||||
|
F64 => code_builder.f64_neg(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NumSin => return NotImplemented,
|
||||||
|
NumCos => return NotImplemented,
|
||||||
|
NumSqrtUnchecked => return NotImplemented,
|
||||||
|
NumLogUnchecked => return NotImplemented,
|
||||||
|
NumRound => {
|
||||||
|
// FIXME
|
||||||
|
// thread 'gen_num::f64_round' panicked at 'called `Result::unwrap()` on an `Err` value:
|
||||||
|
// Io(Os { code: 2, kind: NotFound, message: "No such file or directory" })',
|
||||||
|
// compiler/test_gen/src/helpers/wasm.rs:185:53
|
||||||
|
// Note: Wasm has a `nearest` op, but it does round-to-even when fraction is exactly 0.5
|
||||||
|
// which fails tests. Will this do? Or is specific behaviour important?
|
||||||
|
let width = float_width_from_layout(ret_layout);
|
||||||
|
return BuiltinCall(&bitcode::NUM_ROUND[width]);
|
||||||
|
}
|
||||||
|
NumToFloat => match (ret_layout.value_type(), storage.get(&args[0]).value_type()) {
|
||||||
|
(F32, I32) => code_builder.f32_convert_s_i32(),
|
||||||
|
(F32, I64) => code_builder.f32_convert_s_i64(),
|
||||||
|
(F32, F32) => {}
|
||||||
|
(F32, F64) => code_builder.f32_demote_f64(),
|
||||||
|
(F64, I32) => code_builder.f64_convert_s_i32(),
|
||||||
|
(F64, I64) => code_builder.f64_convert_s_i64(),
|
||||||
|
(F64, F32) => code_builder.f64_promote_f32(),
|
||||||
|
(F64, F64) => {}
|
||||||
|
_ => panic_ret_type(),
|
||||||
|
},
|
||||||
|
NumPow => return NotImplemented,
|
||||||
|
NumCeiling => match ret_layout.value_type() {
|
||||||
|
I32 => {
|
||||||
|
code_builder.f32_ceil();
|
||||||
|
code_builder.i32_trunc_s_f32()
|
||||||
|
}
|
||||||
|
I64 => {
|
||||||
|
code_builder.f64_ceil();
|
||||||
|
code_builder.i64_trunc_s_f64()
|
||||||
|
}
|
||||||
|
_ => panic_ret_type(),
|
||||||
|
},
|
||||||
|
NumPowInt => return NotImplemented,
|
||||||
|
NumFloor => match ret_layout.value_type() {
|
||||||
|
I32 => {
|
||||||
|
code_builder.f32_floor();
|
||||||
|
code_builder.i32_trunc_s_f32()
|
||||||
|
}
|
||||||
|
I64 => {
|
||||||
|
code_builder.f64_floor();
|
||||||
|
code_builder.i64_trunc_s_f64()
|
||||||
|
}
|
||||||
|
_ => panic_ret_type(),
|
||||||
|
},
|
||||||
|
NumIsFinite => match ret_layout.value_type() {
|
||||||
|
I32 => code_builder.i32_const(1),
|
||||||
|
I64 => code_builder.i32_const(1),
|
||||||
|
F32 => {
|
||||||
|
code_builder.i32_reinterpret_f32();
|
||||||
|
code_builder.i32_const(0x7f800000);
|
||||||
|
code_builder.i32_and();
|
||||||
|
code_builder.i32_const(0x7f800000);
|
||||||
|
code_builder.i32_ne();
|
||||||
|
}
|
||||||
|
F64 => {
|
||||||
|
code_builder.i64_reinterpret_f64();
|
||||||
|
code_builder.i64_const(0x7ff0000000000000);
|
||||||
|
code_builder.i64_and();
|
||||||
|
code_builder.i64_const(0x7ff0000000000000);
|
||||||
|
code_builder.i64_ne();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NumAtan => {
|
||||||
|
let width = float_width_from_layout(ret_layout);
|
||||||
|
return BuiltinCall(&bitcode::NUM_ATAN[width]);
|
||||||
|
}
|
||||||
|
NumAcos => {
|
||||||
|
let width = float_width_from_layout(ret_layout);
|
||||||
|
return BuiltinCall(&bitcode::NUM_ACOS[width]);
|
||||||
|
}
|
||||||
|
NumAsin => {
|
||||||
|
let width = float_width_from_layout(ret_layout);
|
||||||
|
return BuiltinCall(&bitcode::NUM_ASIN[width]);
|
||||||
|
}
|
||||||
|
NumBytesToU16 => return NotImplemented,
|
||||||
|
NumBytesToU32 => return NotImplemented,
|
||||||
|
NumBitwiseAnd => match ret_layout.value_type() {
|
||||||
|
I32 => code_builder.i32_and(),
|
||||||
|
I64 => code_builder.i64_and(),
|
||||||
|
_ => panic_ret_type(),
|
||||||
|
},
|
||||||
|
NumBitwiseXor => match ret_layout.value_type() {
|
||||||
|
I32 => code_builder.i32_xor(),
|
||||||
|
I64 => code_builder.i64_xor(),
|
||||||
|
_ => panic_ret_type(),
|
||||||
|
},
|
||||||
|
NumBitwiseOr => match ret_layout.value_type() {
|
||||||
|
I32 => code_builder.i32_or(),
|
||||||
|
I64 => code_builder.i64_or(),
|
||||||
|
_ => panic_ret_type(),
|
||||||
|
},
|
||||||
|
NumShiftLeftBy => {
|
||||||
|
// Unfortunate local.set/local.get
|
||||||
|
storage.load_symbols(code_builder, &[args[1], args[0]]);
|
||||||
|
match ret_layout.value_type() {
|
||||||
|
I32 => code_builder.i32_shl(),
|
||||||
|
I64 => code_builder.i64_shl(),
|
||||||
|
_ => panic_ret_type(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NumShiftRightBy => match ret_layout.value_type() {
|
||||||
|
I32 => code_builder.i32_shr_s(),
|
||||||
|
I64 => code_builder.i64_shr_s(),
|
||||||
|
_ => panic_ret_type(),
|
||||||
|
},
|
||||||
|
NumShiftRightZfBy => match ret_layout.value_type() {
|
||||||
|
I32 => code_builder.i32_shr_u(),
|
||||||
|
I64 => code_builder.i64_shr_u(),
|
||||||
|
_ => panic_ret_type(),
|
||||||
|
},
|
||||||
|
NumIntCast => match (ret_layout.value_type(), storage.get(&args[0]).value_type()) {
|
||||||
|
(I32, I32) => {}
|
||||||
|
(I32, I64) => code_builder.i32_wrap_i64(),
|
||||||
|
(I32, F32) => code_builder.i32_trunc_s_f32(),
|
||||||
|
(I32, F64) => code_builder.i32_trunc_s_f64(),
|
||||||
|
|
||||||
|
(I64, I32) => code_builder.i64_extend_s_i32(),
|
||||||
|
(I64, I64) => {}
|
||||||
|
(I64, F32) => code_builder.i64_trunc_s_f32(),
|
||||||
|
(I64, F64) => code_builder.i64_trunc_s_f64(),
|
||||||
|
|
||||||
|
(F32, I32) => code_builder.f32_convert_s_i32(),
|
||||||
|
(F32, I64) => code_builder.f32_convert_s_i64(),
|
||||||
|
(F32, F32) => {}
|
||||||
|
(F32, F64) => code_builder.f32_demote_f64(),
|
||||||
|
|
||||||
|
(F64, I32) => code_builder.f64_convert_s_i32(),
|
||||||
|
(F64, I64) => code_builder.f64_convert_s_i64(),
|
||||||
|
(F64, F32) => code_builder.f64_promote_f32(),
|
||||||
|
(F64, F64) => {}
|
||||||
|
},
|
||||||
|
Eq => {
|
||||||
|
// TODO: For non-number types, this will implement pointer equality, which is wrong
|
||||||
|
match storage.get(&args[0]).value_type() {
|
||||||
|
I32 => code_builder.i32_eq(),
|
||||||
|
I64 => code_builder.i64_eq(),
|
||||||
|
F32 => code_builder.f32_eq(),
|
||||||
|
F64 => code_builder.f64_eq(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NotEq => {
|
||||||
|
// TODO: For non-number types, this will implement pointer inequality, which is wrong
|
||||||
|
match storage.get(&args[0]).value_type() {
|
||||||
|
I32 => code_builder.i32_ne(),
|
||||||
|
I64 => code_builder.i64_ne(),
|
||||||
|
F32 => code_builder.f32_ne(),
|
||||||
|
F64 => code_builder.f64_ne(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
And => code_builder.i32_and(),
|
||||||
|
Or => code_builder.i32_or(),
|
||||||
|
Not => code_builder.i32_eqz(),
|
||||||
|
Hash => return NotImplemented,
|
||||||
|
ExpectTrue => return NotImplemented,
|
||||||
|
}
|
||||||
|
Done
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrap an integer whose Wasm representation is i32
|
||||||
|
fn wrap_i32(code_builder: &mut CodeBuilder, size: u32) {
|
||||||
|
match size {
|
||||||
|
1 => {
|
||||||
|
// Underlying Roc value is i8
|
||||||
|
code_builder.i32_const(24);
|
||||||
|
code_builder.i32_shl();
|
||||||
|
code_builder.i32_const(24);
|
||||||
|
code_builder.i32_shr_s();
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
// Underlying Roc value is i16
|
||||||
|
code_builder.i32_const(16);
|
||||||
|
code_builder.i32_shl();
|
||||||
|
code_builder.i32_const(16);
|
||||||
|
code_builder.i32_shr_s();
|
||||||
|
}
|
||||||
|
_ => {} // the only other possible value is 4, and i32 wraps natively
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn float_width_from_layout(wasm_layout: &WasmLayout) -> FloatWidth {
|
||||||
|
if wasm_layout.value_type() == ValueType::F32 {
|
||||||
|
FloatWidth::F32
|
||||||
|
} else {
|
||||||
|
FloatWidth::F64
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ use std::fmt::Debug;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
|
|
||||||
use super::linking::{IndexRelocType, OffsetRelocType, RelocationEntry};
|
use super::linking::{IndexRelocType, OffsetRelocType, RelocationEntry};
|
||||||
use super::opcodes::*;
|
use super::opcodes::{OpCode, OpCode::*};
|
||||||
use super::serialize::{SerialBuffer, Serialize};
|
use super::serialize::{SerialBuffer, Serialize};
|
||||||
use crate::{round_up_to_alignment, FRAME_ALIGNMENT_BYTES, STACK_POINTER_GLOBAL_ID};
|
use crate::{round_up_to_alignment, FRAME_ALIGNMENT_BYTES, STACK_POINTER_GLOBAL_ID};
|
||||||
|
|
||||||
|
@ -244,7 +244,7 @@ impl<'a> CodeBuilder<'a> {
|
||||||
// Symbol is not on top of the stack. Find it.
|
// Symbol is not on top of the stack. Find it.
|
||||||
if let Some(found_index) = self.vm_stack.iter().rposition(|&s| s == symbol) {
|
if let Some(found_index) = self.vm_stack.iter().rposition(|&s| s == symbol) {
|
||||||
// Insert a local.set where the value was created
|
// Insert a local.set where the value was created
|
||||||
self.add_insertion(pushed_at, SETLOCAL, next_local_id.0);
|
self.add_insertion(pushed_at, SETLOCAL as u8, next_local_id.0);
|
||||||
|
|
||||||
// Take the value out of the stack where local.set was inserted
|
// Take the value out of the stack where local.set was inserted
|
||||||
self.vm_stack.remove(found_index);
|
self.vm_stack.remove(found_index);
|
||||||
|
@ -267,7 +267,7 @@ impl<'a> CodeBuilder<'a> {
|
||||||
Popped { pushed_at } => {
|
Popped { pushed_at } => {
|
||||||
// This Symbol is being used for a second time
|
// This Symbol is being used for a second time
|
||||||
// Insert a local.tee where it was pushed, so we don't interfere with the first usage
|
// Insert a local.tee where it was pushed, so we don't interfere with the first usage
|
||||||
self.add_insertion(pushed_at, TEELOCAL, next_local_id.0);
|
self.add_insertion(pushed_at, TEELOCAL as u8, next_local_id.0);
|
||||||
|
|
||||||
// Insert a local.get at the current position
|
// Insert a local.get at the current position
|
||||||
self.get_local(next_local_id);
|
self.get_local(next_local_id);
|
||||||
|
@ -331,14 +331,14 @@ impl<'a> CodeBuilder<'a> {
|
||||||
fn build_stack_frame_push(&mut self, frame_size: i32, frame_pointer: LocalId) {
|
fn build_stack_frame_push(&mut self, frame_size: i32, frame_pointer: LocalId) {
|
||||||
// Can't use the usual instruction methods because they push to self.code.
|
// Can't use the usual instruction methods because they push to self.code.
|
||||||
// This is the only case where we push instructions somewhere different.
|
// This is the only case where we push instructions somewhere different.
|
||||||
self.preamble.push(GETGLOBAL);
|
self.preamble.push(GETGLOBAL as u8);
|
||||||
self.preamble.encode_u32(STACK_POINTER_GLOBAL_ID);
|
self.preamble.encode_u32(STACK_POINTER_GLOBAL_ID);
|
||||||
self.preamble.push(I32CONST);
|
self.preamble.push(I32CONST as u8);
|
||||||
self.preamble.encode_i32(frame_size);
|
self.preamble.encode_i32(frame_size);
|
||||||
self.preamble.push(I32SUB);
|
self.preamble.push(I32SUB as u8);
|
||||||
self.preamble.push(TEELOCAL);
|
self.preamble.push(TEELOCAL as u8);
|
||||||
self.preamble.encode_u32(frame_pointer.0);
|
self.preamble.encode_u32(frame_pointer.0);
|
||||||
self.preamble.push(SETGLOBAL);
|
self.preamble.push(SETGLOBAL as u8);
|
||||||
self.preamble.encode_u32(STACK_POINTER_GLOBAL_ID);
|
self.preamble.encode_u32(STACK_POINTER_GLOBAL_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,7 +366,7 @@ impl<'a> CodeBuilder<'a> {
|
||||||
self.build_stack_frame_pop(aligned_size, frame_ptr_id);
|
self.build_stack_frame_pop(aligned_size, frame_ptr_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.code.push(END);
|
self.code.push(END as u8);
|
||||||
|
|
||||||
let inner_len = self.preamble.len() + self.code.len() + self.insert_bytes.len();
|
let inner_len = self.preamble.len() + self.code.len() + self.insert_bytes.len();
|
||||||
self.inner_length.encode_u32(inner_len as u32);
|
self.inner_length.encode_u32(inner_len as u32);
|
||||||
|
@ -433,27 +433,28 @@ impl<'a> CodeBuilder<'a> {
|
||||||
|
|
||||||
/// Base method for generating instructions
|
/// Base method for generating instructions
|
||||||
/// Emits the opcode and simulates VM stack push/pop
|
/// Emits the opcode and simulates VM stack push/pop
|
||||||
fn inst(&mut self, opcode: u8, pops: usize, push: bool) {
|
fn inst(&mut self, opcode: OpCode, pops: usize, push: bool) {
|
||||||
let new_len = self.vm_stack.len() - pops as usize;
|
let new_len = self.vm_stack.len() - pops as usize;
|
||||||
self.vm_stack.truncate(new_len);
|
self.vm_stack.truncate(new_len);
|
||||||
if push {
|
if push {
|
||||||
self.vm_stack.push(Symbol::WASM_ANONYMOUS_STACK_VALUE);
|
self.vm_stack.push(Symbol::WASM_ANONYMOUS_STACK_VALUE);
|
||||||
}
|
}
|
||||||
self.code.push(opcode);
|
|
||||||
|
self.code.push(opcode as u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inst_imm8(&mut self, opcode: u8, pops: usize, push: bool, immediate: u8) {
|
fn inst_imm8(&mut self, opcode: OpCode, pops: usize, push: bool, immediate: u8) {
|
||||||
self.inst(opcode, pops, push);
|
self.inst(opcode, pops, push);
|
||||||
self.code.push(immediate);
|
self.code.push(immediate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// public for use in test code
|
// public for use in test code
|
||||||
pub fn inst_imm32(&mut self, opcode: u8, pops: usize, push: bool, immediate: u32) {
|
pub fn inst_imm32(&mut self, opcode: OpCode, pops: usize, push: bool, immediate: u32) {
|
||||||
self.inst(opcode, pops, push);
|
self.inst(opcode, pops, push);
|
||||||
self.code.encode_u32(immediate);
|
self.code.encode_u32(immediate);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inst_mem(&mut self, opcode: u8, pops: usize, push: bool, align: Align, offset: u32) {
|
fn inst_mem(&mut self, opcode: OpCode, pops: usize, push: bool, align: Align, offset: u32) {
|
||||||
self.inst(opcode, pops, push);
|
self.inst(opcode, pops, push);
|
||||||
self.code.push(align as u8);
|
self.code.push(align as u8);
|
||||||
self.code.encode_u32(offset);
|
self.code.encode_u32(offset);
|
||||||
|
@ -526,7 +527,7 @@ impl<'a> CodeBuilder<'a> {
|
||||||
if has_return_val {
|
if has_return_val {
|
||||||
self.vm_stack.push(Symbol::WASM_ANONYMOUS_STACK_VALUE);
|
self.vm_stack.push(Symbol::WASM_ANONYMOUS_STACK_VALUE);
|
||||||
}
|
}
|
||||||
self.code.push(CALL);
|
self.code.push(CALL as u8);
|
||||||
|
|
||||||
// Write the index of the function to be called.
|
// Write the index of the function to be called.
|
||||||
// Also make a RelocationEntry so the linker can see that this byte offset relates to a function by name.
|
// Also make a RelocationEntry so the linker can see that this byte offset relates to a function by name.
|
||||||
|
|
|
@ -1,178 +1,182 @@
|
||||||
pub const UNREACHABLE: u8 = 0x00;
|
#[repr(u8)]
|
||||||
pub const NOP: u8 = 0x01;
|
#[derive(Debug)]
|
||||||
pub const BLOCK: u8 = 0x02;
|
pub enum OpCode {
|
||||||
pub const LOOP: u8 = 0x03;
|
UNREACHABLE = 0x00,
|
||||||
pub const IF: u8 = 0x04;
|
NOP = 0x01,
|
||||||
pub const ELSE: u8 = 0x05;
|
BLOCK = 0x02,
|
||||||
pub const END: u8 = 0x0b;
|
LOOP = 0x03,
|
||||||
pub const BR: u8 = 0x0c;
|
IF = 0x04,
|
||||||
pub const BRIF: u8 = 0x0d;
|
ELSE = 0x05,
|
||||||
pub const BRTABLE: u8 = 0x0e;
|
END = 0x0b,
|
||||||
pub const RETURN: u8 = 0x0f;
|
BR = 0x0c,
|
||||||
pub const CALL: u8 = 0x10;
|
BRIF = 0x0d,
|
||||||
pub const CALLINDIRECT: u8 = 0x11;
|
BRTABLE = 0x0e,
|
||||||
pub const DROP: u8 = 0x1a;
|
RETURN = 0x0f,
|
||||||
pub const SELECT: u8 = 0x1b;
|
CALL = 0x10,
|
||||||
pub const GETLOCAL: u8 = 0x20;
|
CALLINDIRECT = 0x11,
|
||||||
pub const SETLOCAL: u8 = 0x21;
|
DROP = 0x1a,
|
||||||
pub const TEELOCAL: u8 = 0x22;
|
SELECT = 0x1b,
|
||||||
pub const GETGLOBAL: u8 = 0x23;
|
GETLOCAL = 0x20,
|
||||||
pub const SETGLOBAL: u8 = 0x24;
|
SETLOCAL = 0x21,
|
||||||
pub const I32LOAD: u8 = 0x28;
|
TEELOCAL = 0x22,
|
||||||
pub const I64LOAD: u8 = 0x29;
|
GETGLOBAL = 0x23,
|
||||||
pub const F32LOAD: u8 = 0x2a;
|
SETGLOBAL = 0x24,
|
||||||
pub const F64LOAD: u8 = 0x2b;
|
I32LOAD = 0x28,
|
||||||
pub const I32LOAD8S: u8 = 0x2c;
|
I64LOAD = 0x29,
|
||||||
pub const I32LOAD8U: u8 = 0x2d;
|
F32LOAD = 0x2a,
|
||||||
pub const I32LOAD16S: u8 = 0x2e;
|
F64LOAD = 0x2b,
|
||||||
pub const I32LOAD16U: u8 = 0x2f;
|
I32LOAD8S = 0x2c,
|
||||||
pub const I64LOAD8S: u8 = 0x30;
|
I32LOAD8U = 0x2d,
|
||||||
pub const I64LOAD8U: u8 = 0x31;
|
I32LOAD16S = 0x2e,
|
||||||
pub const I64LOAD16S: u8 = 0x32;
|
I32LOAD16U = 0x2f,
|
||||||
pub const I64LOAD16U: u8 = 0x33;
|
I64LOAD8S = 0x30,
|
||||||
pub const I64LOAD32S: u8 = 0x34;
|
I64LOAD8U = 0x31,
|
||||||
pub const I64LOAD32U: u8 = 0x35;
|
I64LOAD16S = 0x32,
|
||||||
pub const I32STORE: u8 = 0x36;
|
I64LOAD16U = 0x33,
|
||||||
pub const I64STORE: u8 = 0x37;
|
I64LOAD32S = 0x34,
|
||||||
pub const F32STORE: u8 = 0x38;
|
I64LOAD32U = 0x35,
|
||||||
pub const F64STORE: u8 = 0x39;
|
I32STORE = 0x36,
|
||||||
pub const I32STORE8: u8 = 0x3a;
|
I64STORE = 0x37,
|
||||||
pub const I32STORE16: u8 = 0x3b;
|
F32STORE = 0x38,
|
||||||
pub const I64STORE8: u8 = 0x3c;
|
F64STORE = 0x39,
|
||||||
pub const I64STORE16: u8 = 0x3d;
|
I32STORE8 = 0x3a,
|
||||||
pub const I64STORE32: u8 = 0x3e;
|
I32STORE16 = 0x3b,
|
||||||
pub const CURRENTMEMORY: u8 = 0x3f;
|
I64STORE8 = 0x3c,
|
||||||
pub const GROWMEMORY: u8 = 0x40;
|
I64STORE16 = 0x3d,
|
||||||
pub const I32CONST: u8 = 0x41;
|
I64STORE32 = 0x3e,
|
||||||
pub const I64CONST: u8 = 0x42;
|
CURRENTMEMORY = 0x3f,
|
||||||
pub const F32CONST: u8 = 0x43;
|
GROWMEMORY = 0x40,
|
||||||
pub const F64CONST: u8 = 0x44;
|
I32CONST = 0x41,
|
||||||
pub const I32EQZ: u8 = 0x45;
|
I64CONST = 0x42,
|
||||||
pub const I32EQ: u8 = 0x46;
|
F32CONST = 0x43,
|
||||||
pub const I32NE: u8 = 0x47;
|
F64CONST = 0x44,
|
||||||
pub const I32LTS: u8 = 0x48;
|
I32EQZ = 0x45,
|
||||||
pub const I32LTU: u8 = 0x49;
|
I32EQ = 0x46,
|
||||||
pub const I32GTS: u8 = 0x4a;
|
I32NE = 0x47,
|
||||||
pub const I32GTU: u8 = 0x4b;
|
I32LTS = 0x48,
|
||||||
pub const I32LES: u8 = 0x4c;
|
I32LTU = 0x49,
|
||||||
pub const I32LEU: u8 = 0x4d;
|
I32GTS = 0x4a,
|
||||||
pub const I32GES: u8 = 0x4e;
|
I32GTU = 0x4b,
|
||||||
pub const I32GEU: u8 = 0x4f;
|
I32LES = 0x4c,
|
||||||
pub const I64EQZ: u8 = 0x50;
|
I32LEU = 0x4d,
|
||||||
pub const I64EQ: u8 = 0x51;
|
I32GES = 0x4e,
|
||||||
pub const I64NE: u8 = 0x52;
|
I32GEU = 0x4f,
|
||||||
pub const I64LTS: u8 = 0x53;
|
I64EQZ = 0x50,
|
||||||
pub const I64LTU: u8 = 0x54;
|
I64EQ = 0x51,
|
||||||
pub const I64GTS: u8 = 0x55;
|
I64NE = 0x52,
|
||||||
pub const I64GTU: u8 = 0x56;
|
I64LTS = 0x53,
|
||||||
pub const I64LES: u8 = 0x57;
|
I64LTU = 0x54,
|
||||||
pub const I64LEU: u8 = 0x58;
|
I64GTS = 0x55,
|
||||||
pub const I64GES: u8 = 0x59;
|
I64GTU = 0x56,
|
||||||
pub const I64GEU: u8 = 0x5a;
|
I64LES = 0x57,
|
||||||
|
I64LEU = 0x58,
|
||||||
|
I64GES = 0x59,
|
||||||
|
I64GEU = 0x5a,
|
||||||
|
|
||||||
pub const F32EQ: u8 = 0x5b;
|
F32EQ = 0x5b,
|
||||||
pub const F32NE: u8 = 0x5c;
|
F32NE = 0x5c,
|
||||||
pub const F32LT: u8 = 0x5d;
|
F32LT = 0x5d,
|
||||||
pub const F32GT: u8 = 0x5e;
|
F32GT = 0x5e,
|
||||||
pub const F32LE: u8 = 0x5f;
|
F32LE = 0x5f,
|
||||||
pub const F32GE: u8 = 0x60;
|
F32GE = 0x60,
|
||||||
|
|
||||||
pub const F64EQ: u8 = 0x61;
|
F64EQ = 0x61,
|
||||||
pub const F64NE: u8 = 0x62;
|
F64NE = 0x62,
|
||||||
pub const F64LT: u8 = 0x63;
|
F64LT = 0x63,
|
||||||
pub const F64GT: u8 = 0x64;
|
F64GT = 0x64,
|
||||||
pub const F64LE: u8 = 0x65;
|
F64LE = 0x65,
|
||||||
pub const F64GE: u8 = 0x66;
|
F64GE = 0x66,
|
||||||
|
|
||||||
pub const I32CLZ: u8 = 0x67;
|
I32CLZ = 0x67,
|
||||||
pub const I32CTZ: u8 = 0x68;
|
I32CTZ = 0x68,
|
||||||
pub const I32POPCNT: u8 = 0x69;
|
I32POPCNT = 0x69,
|
||||||
pub const I32ADD: u8 = 0x6a;
|
I32ADD = 0x6a,
|
||||||
pub const I32SUB: u8 = 0x6b;
|
I32SUB = 0x6b,
|
||||||
pub const I32MUL: u8 = 0x6c;
|
I32MUL = 0x6c,
|
||||||
pub const I32DIVS: u8 = 0x6d;
|
I32DIVS = 0x6d,
|
||||||
pub const I32DIVU: u8 = 0x6e;
|
I32DIVU = 0x6e,
|
||||||
pub const I32REMS: u8 = 0x6f;
|
I32REMS = 0x6f,
|
||||||
pub const I32REMU: u8 = 0x70;
|
I32REMU = 0x70,
|
||||||
pub const I32AND: u8 = 0x71;
|
I32AND = 0x71,
|
||||||
pub const I32OR: u8 = 0x72;
|
I32OR = 0x72,
|
||||||
pub const I32XOR: u8 = 0x73;
|
I32XOR = 0x73,
|
||||||
pub const I32SHL: u8 = 0x74;
|
I32SHL = 0x74,
|
||||||
pub const I32SHRS: u8 = 0x75;
|
I32SHRS = 0x75,
|
||||||
pub const I32SHRU: u8 = 0x76;
|
I32SHRU = 0x76,
|
||||||
pub const I32ROTL: u8 = 0x77;
|
I32ROTL = 0x77,
|
||||||
pub const I32ROTR: u8 = 0x78;
|
I32ROTR = 0x78,
|
||||||
|
|
||||||
pub const I64CLZ: u8 = 0x79;
|
I64CLZ = 0x79,
|
||||||
pub const I64CTZ: u8 = 0x7a;
|
I64CTZ = 0x7a,
|
||||||
pub const I64POPCNT: u8 = 0x7b;
|
I64POPCNT = 0x7b,
|
||||||
pub const I64ADD: u8 = 0x7c;
|
I64ADD = 0x7c,
|
||||||
pub const I64SUB: u8 = 0x7d;
|
I64SUB = 0x7d,
|
||||||
pub const I64MUL: u8 = 0x7e;
|
I64MUL = 0x7e,
|
||||||
pub const I64DIVS: u8 = 0x7f;
|
I64DIVS = 0x7f,
|
||||||
pub const I64DIVU: u8 = 0x80;
|
I64DIVU = 0x80,
|
||||||
pub const I64REMS: u8 = 0x81;
|
I64REMS = 0x81,
|
||||||
pub const I64REMU: u8 = 0x82;
|
I64REMU = 0x82,
|
||||||
pub const I64AND: u8 = 0x83;
|
I64AND = 0x83,
|
||||||
pub const I64OR: u8 = 0x84;
|
I64OR = 0x84,
|
||||||
pub const I64XOR: u8 = 0x85;
|
I64XOR = 0x85,
|
||||||
pub const I64SHL: u8 = 0x86;
|
I64SHL = 0x86,
|
||||||
pub const I64SHRS: u8 = 0x87;
|
I64SHRS = 0x87,
|
||||||
pub const I64SHRU: u8 = 0x88;
|
I64SHRU = 0x88,
|
||||||
pub const I64ROTL: u8 = 0x89;
|
I64ROTL = 0x89,
|
||||||
pub const I64ROTR: u8 = 0x8a;
|
I64ROTR = 0x8a,
|
||||||
pub const F32ABS: u8 = 0x8b;
|
F32ABS = 0x8b,
|
||||||
pub const F32NEG: u8 = 0x8c;
|
F32NEG = 0x8c,
|
||||||
pub const F32CEIL: u8 = 0x8d;
|
F32CEIL = 0x8d,
|
||||||
pub const F32FLOOR: u8 = 0x8e;
|
F32FLOOR = 0x8e,
|
||||||
pub const F32TRUNC: u8 = 0x8f;
|
F32TRUNC = 0x8f,
|
||||||
pub const F32NEAREST: u8 = 0x90;
|
F32NEAREST = 0x90,
|
||||||
pub const F32SQRT: u8 = 0x91;
|
F32SQRT = 0x91,
|
||||||
pub const F32ADD: u8 = 0x92;
|
F32ADD = 0x92,
|
||||||
pub const F32SUB: u8 = 0x93;
|
F32SUB = 0x93,
|
||||||
pub const F32MUL: u8 = 0x94;
|
F32MUL = 0x94,
|
||||||
pub const F32DIV: u8 = 0x95;
|
F32DIV = 0x95,
|
||||||
pub const F32MIN: u8 = 0x96;
|
F32MIN = 0x96,
|
||||||
pub const F32MAX: u8 = 0x97;
|
F32MAX = 0x97,
|
||||||
pub const F32COPYSIGN: u8 = 0x98;
|
F32COPYSIGN = 0x98,
|
||||||
pub const F64ABS: u8 = 0x99;
|
F64ABS = 0x99,
|
||||||
pub const F64NEG: u8 = 0x9a;
|
F64NEG = 0x9a,
|
||||||
pub const F64CEIL: u8 = 0x9b;
|
F64CEIL = 0x9b,
|
||||||
pub const F64FLOOR: u8 = 0x9c;
|
F64FLOOR = 0x9c,
|
||||||
pub const F64TRUNC: u8 = 0x9d;
|
F64TRUNC = 0x9d,
|
||||||
pub const F64NEAREST: u8 = 0x9e;
|
F64NEAREST = 0x9e,
|
||||||
pub const F64SQRT: u8 = 0x9f;
|
F64SQRT = 0x9f,
|
||||||
pub const F64ADD: u8 = 0xa0;
|
F64ADD = 0xa0,
|
||||||
pub const F64SUB: u8 = 0xa1;
|
F64SUB = 0xa1,
|
||||||
pub const F64MUL: u8 = 0xa2;
|
F64MUL = 0xa2,
|
||||||
pub const F64DIV: u8 = 0xa3;
|
F64DIV = 0xa3,
|
||||||
pub const F64MIN: u8 = 0xa4;
|
F64MIN = 0xa4,
|
||||||
pub const F64MAX: u8 = 0xa5;
|
F64MAX = 0xa5,
|
||||||
pub const F64COPYSIGN: u8 = 0xa6;
|
F64COPYSIGN = 0xa6,
|
||||||
|
|
||||||
pub const I32WRAPI64: u8 = 0xa7;
|
I32WRAPI64 = 0xa7,
|
||||||
pub const I32TRUNCSF32: u8 = 0xa8;
|
I32TRUNCSF32 = 0xa8,
|
||||||
pub const I32TRUNCUF32: u8 = 0xa9;
|
I32TRUNCUF32 = 0xa9,
|
||||||
pub const I32TRUNCSF64: u8 = 0xaa;
|
I32TRUNCSF64 = 0xaa,
|
||||||
pub const I32TRUNCUF64: u8 = 0xab;
|
I32TRUNCUF64 = 0xab,
|
||||||
pub const I64EXTENDSI32: u8 = 0xac;
|
I64EXTENDSI32 = 0xac,
|
||||||
pub const I64EXTENDUI32: u8 = 0xad;
|
I64EXTENDUI32 = 0xad,
|
||||||
pub const I64TRUNCSF32: u8 = 0xae;
|
I64TRUNCSF32 = 0xae,
|
||||||
pub const I64TRUNCUF32: u8 = 0xaf;
|
I64TRUNCUF32 = 0xaf,
|
||||||
pub const I64TRUNCSF64: u8 = 0xb0;
|
I64TRUNCSF64 = 0xb0,
|
||||||
pub const I64TRUNCUF64: u8 = 0xb1;
|
I64TRUNCUF64 = 0xb1,
|
||||||
pub const F32CONVERTSI32: u8 = 0xb2;
|
F32CONVERTSI32 = 0xb2,
|
||||||
pub const F32CONVERTUI32: u8 = 0xb3;
|
F32CONVERTUI32 = 0xb3,
|
||||||
pub const F32CONVERTSI64: u8 = 0xb4;
|
F32CONVERTSI64 = 0xb4,
|
||||||
pub const F32CONVERTUI64: u8 = 0xb5;
|
F32CONVERTUI64 = 0xb5,
|
||||||
pub const F32DEMOTEF64: u8 = 0xb6;
|
F32DEMOTEF64 = 0xb6,
|
||||||
pub const F64CONVERTSI32: u8 = 0xb7;
|
F64CONVERTSI32 = 0xb7,
|
||||||
pub const F64CONVERTUI32: u8 = 0xb8;
|
F64CONVERTUI32 = 0xb8,
|
||||||
pub const F64CONVERTSI64: u8 = 0xb9;
|
F64CONVERTSI64 = 0xb9,
|
||||||
pub const F64CONVERTUI64: u8 = 0xba;
|
F64CONVERTUI64 = 0xba,
|
||||||
pub const F64PROMOTEF32: u8 = 0xbb;
|
F64PROMOTEF32 = 0xbb,
|
||||||
|
|
||||||
pub const I32REINTERPRETF32: u8 = 0xbc;
|
I32REINTERPRETF32 = 0xbc,
|
||||||
pub const I64REINTERPRETF64: u8 = 0xbd;
|
I64REINTERPRETF64 = 0xbd,
|
||||||
pub const F32REINTERPRETI32: u8 = 0xbe;
|
F32REINTERPRETI32 = 0xbe,
|
||||||
pub const F64REINTERPRETI64: u8 = 0xbf;
|
F64REINTERPRETI64 = 0xbf,
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use bumpalo::Bump;
|
||||||
use super::linking::{
|
use super::linking::{
|
||||||
IndexRelocType, LinkingSection, RelocationEntry, RelocationSection, SymInfo, WasmObjectSymbol,
|
IndexRelocType, LinkingSection, RelocationEntry, RelocationSection, SymInfo, WasmObjectSymbol,
|
||||||
};
|
};
|
||||||
use super::opcodes;
|
use super::opcodes::OpCode;
|
||||||
use super::serialize::{SerialBuffer, Serialize};
|
use super::serialize::{SerialBuffer, Serialize};
|
||||||
use super::{CodeBuilder, ValueType};
|
use super::{CodeBuilder, ValueType};
|
||||||
|
|
||||||
|
@ -353,23 +353,23 @@ impl Serialize for ConstExpr {
|
||||||
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
|
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
|
||||||
match self {
|
match self {
|
||||||
ConstExpr::I32(x) => {
|
ConstExpr::I32(x) => {
|
||||||
buffer.append_u8(opcodes::I32CONST);
|
buffer.append_u8(OpCode::I32CONST as u8);
|
||||||
buffer.encode_i32(*x);
|
buffer.encode_i32(*x);
|
||||||
}
|
}
|
||||||
ConstExpr::I64(x) => {
|
ConstExpr::I64(x) => {
|
||||||
buffer.append_u8(opcodes::I64CONST);
|
buffer.append_u8(OpCode::I64CONST as u8);
|
||||||
buffer.encode_i64(*x);
|
buffer.encode_i64(*x);
|
||||||
}
|
}
|
||||||
ConstExpr::F32(x) => {
|
ConstExpr::F32(x) => {
|
||||||
buffer.append_u8(opcodes::F32CONST);
|
buffer.append_u8(OpCode::F32CONST as u8);
|
||||||
buffer.encode_f32(*x);
|
buffer.encode_f32(*x);
|
||||||
}
|
}
|
||||||
ConstExpr::F64(x) => {
|
ConstExpr::F64(x) => {
|
||||||
buffer.append_u8(opcodes::F64CONST);
|
buffer.append_u8(OpCode::F64CONST as u8);
|
||||||
buffer.encode_f64(*x);
|
buffer.encode_f64(*x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buffer.append_u8(opcodes::END);
|
buffer.append_u8(OpCode::END as u8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1734,7 +1734,7 @@ fn update<'a>(
|
||||||
let mut shorthands = (*state.arc_shorthands).lock();
|
let mut shorthands = (*state.arc_shorthands).lock();
|
||||||
|
|
||||||
for (shorthand, package_or_path) in header.packages.iter() {
|
for (shorthand, package_or_path) in header.packages.iter() {
|
||||||
shorthands.insert(shorthand, package_or_path.clone());
|
shorthands.insert(shorthand, *package_or_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let PkgConfig {
|
if let PkgConfig {
|
||||||
|
@ -2273,7 +2273,7 @@ fn finish_specialization(
|
||||||
let package_or_path = match platform_path {
|
let package_or_path = match platform_path {
|
||||||
Valid(To::ExistingPackage(shorthand)) => {
|
Valid(To::ExistingPackage(shorthand)) => {
|
||||||
match (*state.arc_shorthands).lock().get(shorthand) {
|
match (*state.arc_shorthands).lock().get(shorthand) {
|
||||||
Some(p_or_p) => p_or_p.clone(),
|
Some(p_or_p) => *p_or_p,
|
||||||
None => unreachable!(),
|
None => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2978,7 +2978,7 @@ fn send_header<'a>(
|
||||||
package_or_path,
|
package_or_path,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
package_entries.insert(*shorthand, package_or_path.value.clone());
|
package_entries.insert(*shorthand, package_or_path.value);
|
||||||
}
|
}
|
||||||
SpaceBefore(inner, _) | SpaceAfter(inner, _) => {
|
SpaceBefore(inner, _) | SpaceAfter(inner, _) => {
|
||||||
parse_entries.push(inner);
|
parse_entries.push(inner);
|
||||||
|
@ -3211,7 +3211,7 @@ fn send_header_two<'a>(
|
||||||
package_or_path,
|
package_or_path,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
package_entries.insert(*shorthand, package_or_path.value.clone());
|
package_entries.insert(*shorthand, package_or_path.value);
|
||||||
}
|
}
|
||||||
SpaceBefore(inner, _) | SpaceAfter(inner, _) => {
|
SpaceBefore(inner, _) | SpaceAfter(inner, _) => {
|
||||||
parse_entries.push(inner);
|
parse_entries.push(inner);
|
||||||
|
|
|
@ -1070,6 +1070,7 @@ define_builtins! {
|
||||||
46 LIST_TAKE_LAST: "takeLast"
|
46 LIST_TAKE_LAST: "takeLast"
|
||||||
47 LIST_FIND: "find"
|
47 LIST_FIND: "find"
|
||||||
48 LIST_FIND_RESULT: "#find_result" // symbol used in the definition of List.find
|
48 LIST_FIND_RESULT: "#find_result" // symbol used in the definition of List.find
|
||||||
|
49 LIST_SUBLIST: "sublist"
|
||||||
}
|
}
|
||||||
5 RESULT: "Result" => {
|
5 RESULT: "Result" => {
|
||||||
0 RESULT_RESULT: "Result" imported // the Result.Result type alias
|
0 RESULT_RESULT: "Result" imported // the Result.Result type alias
|
||||||
|
|
|
@ -19,11 +19,4 @@ ven_pretty = { path = "../../vendor/pretty" }
|
||||||
morphic_lib = { path = "../../vendor/morphic_lib" }
|
morphic_lib = { path = "../../vendor/morphic_lib" }
|
||||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
hashbrown = { version = "0.11.2", features = [ "bumpalo" ] }
|
hashbrown = { version = "0.11.2", features = [ "bumpalo" ] }
|
||||||
ven_ena = { path = "../../vendor/ena" }
|
|
||||||
ven_graph = { path = "../../vendor/pathfinding" }
|
ven_graph = { path = "../../vendor/pathfinding" }
|
||||||
linked-hash-map = "0.5.4"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
roc_builtins = { path = "../builtins" }
|
|
||||||
roc_parse = { path = "../parse" }
|
|
||||||
roc_solve = { path = "../solve" }
|
|
||||||
|
|
|
@ -1,8 +1,46 @@
|
||||||
|
/// UNUSED
|
||||||
|
///
|
||||||
|
/// but kept for future reference
|
||||||
|
///
|
||||||
|
///
|
||||||
|
// pub fn optimize_refcount_operations<'i, T>(
|
||||||
|
// arena: &'a Bump,
|
||||||
|
// home: ModuleId,
|
||||||
|
// ident_ids: &'i mut IdentIds,
|
||||||
|
// procs: &mut MutMap<T, Proc<'a>>,
|
||||||
|
// ) {
|
||||||
|
// use crate::expand_rc;
|
||||||
|
//
|
||||||
|
// let deferred = expand_rc::Deferred {
|
||||||
|
// inc_dec_map: Default::default(),
|
||||||
|
// assignments: Vec::new_in(arena),
|
||||||
|
// decrefs: Vec::new_in(arena),
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// let mut env = expand_rc::Env {
|
||||||
|
// home,
|
||||||
|
// arena,
|
||||||
|
// ident_ids,
|
||||||
|
// layout_map: Default::default(),
|
||||||
|
// alias_map: Default::default(),
|
||||||
|
// constructor_map: Default::default(),
|
||||||
|
// deferred,
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// for (_, proc) in procs.iter_mut() {
|
||||||
|
// let b = expand_rc::expand_and_cancel_proc(
|
||||||
|
// &mut env,
|
||||||
|
// arena.alloc(proc.body.clone()),
|
||||||
|
// proc.args,
|
||||||
|
// );
|
||||||
|
// proc.body = b.clone();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
use crate::ir::{BranchInfo, Expr, ModifyRc, Stmt};
|
use crate::ir::{BranchInfo, Expr, ModifyRc, Stmt};
|
||||||
use crate::layout::{Layout, UnionLayout};
|
use crate::layout::{Layout, UnionLayout};
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use linked_hash_map::LinkedHashMap;
|
// use linked_hash_map::LinkedHashMap;
|
||||||
use roc_collections::all::MutMap;
|
use roc_collections::all::MutMap;
|
||||||
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
||||||
|
|
||||||
|
|
|
@ -370,40 +370,6 @@ impl<'a> Proc<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn optimize_refcount_operations<'i, T>(
|
|
||||||
arena: &'a Bump,
|
|
||||||
home: ModuleId,
|
|
||||||
ident_ids: &'i mut IdentIds,
|
|
||||||
procs: &mut MutMap<T, Proc<'a>>,
|
|
||||||
) {
|
|
||||||
use crate::expand_rc;
|
|
||||||
|
|
||||||
let deferred = expand_rc::Deferred {
|
|
||||||
inc_dec_map: Default::default(),
|
|
||||||
assignments: Vec::new_in(arena),
|
|
||||||
decrefs: Vec::new_in(arena),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut env = expand_rc::Env {
|
|
||||||
home,
|
|
||||||
arena,
|
|
||||||
ident_ids,
|
|
||||||
layout_map: Default::default(),
|
|
||||||
alias_map: Default::default(),
|
|
||||||
constructor_map: Default::default(),
|
|
||||||
deferred,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (_, proc) in procs.iter_mut() {
|
|
||||||
let b = expand_rc::expand_and_cancel_proc(
|
|
||||||
&mut env,
|
|
||||||
arena.alloc(proc.body.clone()),
|
|
||||||
proc.args,
|
|
||||||
);
|
|
||||||
proc.body = b.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_tail_recursive(&mut self, env: &mut Env<'a, '_>) {
|
fn make_tail_recursive(&mut self, env: &mut Env<'a, '_>) {
|
||||||
let mut args = Vec::with_capacity_in(self.args.len(), env.arena);
|
let mut args = Vec::with_capacity_in(self.args.len(), env.arena);
|
||||||
let mut proc_args = Vec::with_capacity_in(self.args.len(), env.arena);
|
let mut proc_args = Vec::with_capacity_in(self.args.len(), env.arena);
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
pub mod alias_analysis;
|
pub mod alias_analysis;
|
||||||
pub mod borrow;
|
pub mod borrow;
|
||||||
pub mod expand_rc;
|
|
||||||
pub mod inc_dec;
|
pub mod inc_dec;
|
||||||
pub mod ir;
|
pub mod ir;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
|
|
|
@ -9,13 +9,13 @@ use crate::string_literal;
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use roc_region::all::Loc;
|
use roc_region::all::Loc;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub struct PackageName<'a> {
|
pub struct PackageName<'a> {
|
||||||
pub account: &'a str,
|
pub account: &'a str,
|
||||||
pub pkg: &'a str,
|
pub pkg: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub enum Version<'a> {
|
pub enum Version<'a> {
|
||||||
Exact(&'a str),
|
Exact(&'a str),
|
||||||
Range {
|
Range {
|
||||||
|
@ -32,7 +32,7 @@ pub enum VersionComparison {
|
||||||
DisallowsEqual,
|
DisallowsEqual,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
pub enum PackageOrPath<'a> {
|
pub enum PackageOrPath<'a> {
|
||||||
Package(PackageName<'a>, Version<'a>),
|
Package(PackageName<'a>, Version<'a>),
|
||||||
Path(StrLiteral<'a>),
|
Path(StrLiteral<'a>),
|
||||||
|
@ -240,7 +240,7 @@ pub enum TypedIdent<'a> {
|
||||||
SpaceAfter(&'a TypedIdent<'a>, &'a [CommentOrNewline<'a>]),
|
SpaceAfter(&'a TypedIdent<'a>, &'a [CommentOrNewline<'a>]),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub enum PackageEntry<'a> {
|
pub enum PackageEntry<'a> {
|
||||||
Entry {
|
Entry {
|
||||||
shorthand: &'a str,
|
shorthand: &'a str,
|
||||||
|
|
|
@ -586,6 +586,7 @@ struct Packages<'a> {
|
||||||
|
|
||||||
before_packages_keyword: &'a [CommentOrNewline<'a>],
|
before_packages_keyword: &'a [CommentOrNewline<'a>],
|
||||||
after_packages_keyword: &'a [CommentOrNewline<'a>],
|
after_packages_keyword: &'a [CommentOrNewline<'a>],
|
||||||
|
final_comments: &'a [CommentOrNewline<'a>],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -602,21 +603,24 @@ fn packages<'a>() -> impl Parser<'a, Packages<'a>, EPackages<'a>> {
|
||||||
EPackages::IndentPackages,
|
EPackages::IndentPackages,
|
||||||
EPackages::IndentListStart
|
EPackages::IndentListStart
|
||||||
),
|
),
|
||||||
collection_e!(
|
collection_trailing_sep_e!(
|
||||||
word1(b'{', EPackages::ListStart),
|
word1(b'{', EPackages::ListStart),
|
||||||
specialize(EPackages::PackageEntry, loc!(package_entry())),
|
specialize(EPackages::PackageEntry, loc!(package_entry())),
|
||||||
word1(b',', EPackages::ListEnd),
|
word1(b',', EPackages::ListEnd),
|
||||||
word1(b'}', EPackages::ListEnd),
|
word1(b'}', EPackages::ListEnd),
|
||||||
min_indent,
|
min_indent,
|
||||||
|
EPackages::Open,
|
||||||
EPackages::Space,
|
EPackages::Space,
|
||||||
EPackages::IndentListEnd
|
EPackages::IndentListEnd,
|
||||||
|
PackageEntry::SpaceBefore
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|((before_packages_keyword, after_packages_keyword), entries)| {
|
|((before_packages_keyword, after_packages_keyword), (entries, final_comments))| {
|
||||||
Packages {
|
Packages {
|
||||||
entries,
|
entries,
|
||||||
before_packages_keyword,
|
before_packages_keyword,
|
||||||
after_packages_keyword,
|
after_packages_keyword,
|
||||||
|
final_comments,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -265,6 +265,7 @@ pub enum ETypedIdent<'a> {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum EPackages<'a> {
|
pub enum EPackages<'a> {
|
||||||
|
Open(Row, Col),
|
||||||
Space(BadInputError, Row, Col),
|
Space(BadInputError, Row, Col),
|
||||||
Packages(Row, Col),
|
Packages(Row, Col),
|
||||||
IndentPackages(Row, Col),
|
IndentPackages(Row, Col),
|
||||||
|
|
|
@ -3223,6 +3223,62 @@ mod test_parse {
|
||||||
assert_eq!(Ok(expected), actual);
|
assert_eq!(Ok(expected), actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn full_app_header_trailing_commas() {
|
||||||
|
use ExposesEntry::Exposed;
|
||||||
|
use PackageOrPath::Path;
|
||||||
|
|
||||||
|
let newlines = &[Newline];
|
||||||
|
let pkg_entry = PackageEntry::Entry {
|
||||||
|
shorthand: "base",
|
||||||
|
spaces_after_shorthand: &[],
|
||||||
|
package_or_path: Located::new(1, 1, 21, 33, Path(PlainLine("./platform"))),
|
||||||
|
};
|
||||||
|
let loc_pkg_entry = Located::new(1, 1, 15, 33, pkg_entry);
|
||||||
|
let arena = Bump::new();
|
||||||
|
let packages = bumpalo::vec![in &arena; loc_pkg_entry];
|
||||||
|
let import = ImportsEntry::Package("foo", ModuleName::new("Bar.Baz"), Vec::new_in(&arena));
|
||||||
|
let loc_import = Located::new(2, 2, 14, 25, import);
|
||||||
|
let imports = bumpalo::vec![in &arena; loc_import];
|
||||||
|
let provide_entry = Located::new(3, 3, 15, 24, Exposed("quicksort"));
|
||||||
|
let provides = bumpalo::vec![in &arena; provide_entry];
|
||||||
|
let module_name = StrLiteral::PlainLine("quicksort");
|
||||||
|
|
||||||
|
let header = AppHeader {
|
||||||
|
before_header: &[],
|
||||||
|
name: Located::new(0, 0, 4, 15, module_name),
|
||||||
|
packages,
|
||||||
|
imports,
|
||||||
|
provides,
|
||||||
|
to: Located::new(3, 3, 30, 34, To::ExistingPackage("base")),
|
||||||
|
after_app_keyword: &[],
|
||||||
|
before_packages: newlines,
|
||||||
|
after_packages: &[],
|
||||||
|
before_imports: newlines,
|
||||||
|
after_imports: &[],
|
||||||
|
before_provides: newlines,
|
||||||
|
after_provides: &[],
|
||||||
|
before_to: &[],
|
||||||
|
after_to: &[],
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = roc_parse::ast::Module::App { header };
|
||||||
|
|
||||||
|
let src = indoc!(
|
||||||
|
r#"
|
||||||
|
app "quicksort"
|
||||||
|
packages { base: "./platform", }
|
||||||
|
imports [ foo.Bar.Baz ]
|
||||||
|
provides [ quicksort ] to base
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
|
||||||
|
let actual = roc_parse::module::parse_header(&arena, State::new(src.as_bytes()))
|
||||||
|
.map(|tuple| tuple.0);
|
||||||
|
|
||||||
|
assert_eq!(Ok(expected), actual);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_platform_header() {
|
fn empty_platform_header() {
|
||||||
let pkg_name = PackageName {
|
let pkg_name = PackageName {
|
||||||
|
|
|
@ -16,8 +16,6 @@ roc_can = { path = "../can" }
|
||||||
roc_solve = { path = "../solve" }
|
roc_solve = { path = "../solve" }
|
||||||
roc_mono = { path = "../mono" }
|
roc_mono = { path = "../mono" }
|
||||||
ven_pretty = { path = "../../vendor/pretty" }
|
ven_pretty = { path = "../../vendor/pretty" }
|
||||||
im = "15.0.0"
|
|
||||||
im-rc = "15.0.0"
|
|
||||||
distance = "0.4.0"
|
distance = "0.4.0"
|
||||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
|
|
||||||
|
|
|
@ -3781,6 +3781,18 @@ mod solve_expr {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_sublist() {
|
||||||
|
infer_eq_without_problem(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
List.sublist
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
"List a, { len : Nat, start : Nat } -> List a",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn list_drop_last() {
|
fn list_drop_last() {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
|
|
|
@ -29,8 +29,6 @@ roc_can = { path = "../can" }
|
||||||
roc_parse = { path = "../parse" }
|
roc_parse = { path = "../parse" }
|
||||||
roc_build = { path = "../build" }
|
roc_build = { path = "../build" }
|
||||||
roc_std = { path = "../../roc_std" }
|
roc_std = { path = "../../roc_std" }
|
||||||
im = "15.0.0"
|
|
||||||
im-rc = "15.0.0"
|
|
||||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
either = "1.6.1"
|
either = "1.6.1"
|
||||||
libc = "0.2.106"
|
libc = "0.2.106"
|
||||||
|
|
|
@ -208,6 +208,46 @@ fn list_take_last() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn list_sublist() {
|
||||||
|
assert_evals_to!(
|
||||||
|
"List.sublist [1, 2, 3] { start: 0 , len: 2 } ",
|
||||||
|
RocList::from_slice(&[1, 2]),
|
||||||
|
RocList<i64>
|
||||||
|
);
|
||||||
|
assert_evals_to!(
|
||||||
|
"List.sublist [1, 2, 3] { start: 1 , len: 2 } ",
|
||||||
|
RocList::from_slice(&[2, 3]),
|
||||||
|
RocList<i64>
|
||||||
|
);
|
||||||
|
assert_evals_to!(
|
||||||
|
"List.sublist [1, 2, 3] { start: 2 , len: 2 } ",
|
||||||
|
RocList::from_slice(&[3]),
|
||||||
|
RocList<i64>
|
||||||
|
);
|
||||||
|
assert_evals_to!(
|
||||||
|
"List.sublist [1, 2, 3] { start: 3 , len: 2 } ",
|
||||||
|
RocList::from_slice(&[]),
|
||||||
|
RocList<i64>
|
||||||
|
);
|
||||||
|
assert_evals_to!(
|
||||||
|
"List.sublist [] { start: 1 , len: 1 } ",
|
||||||
|
RocList::from_slice(&[]),
|
||||||
|
RocList<i64>
|
||||||
|
);
|
||||||
|
assert_evals_to!(
|
||||||
|
"List.sublist [1, 2, 3] { start: 1 , len: 0 } ",
|
||||||
|
RocList::from_slice(&[]),
|
||||||
|
RocList<i64>
|
||||||
|
);
|
||||||
|
assert_evals_to!(
|
||||||
|
"List.sublist [1, 2, 3] { start: 0 , len: 5 } ",
|
||||||
|
RocList::from_slice(&[1, 2, 3]),
|
||||||
|
RocList<i64>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
fn list_drop() {
|
fn list_drop() {
|
||||||
|
@ -2301,7 +2341,7 @@ fn list_any() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
#[ignore]
|
#[should_panic(expected = r#"Roc failed with message: "UnresolvedTypeVar"#)]
|
||||||
fn list_any_empty_with_unknown_element_type() {
|
fn list_any_empty_with_unknown_element_type() {
|
||||||
// Segfaults with invalid memory reference. Running this as a stand-alone
|
// Segfaults with invalid memory reference. Running this as a stand-alone
|
||||||
// Roc program, generates the following error message:
|
// Roc program, generates the following error message:
|
||||||
|
|
|
@ -530,7 +530,7 @@ fn f64_round() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||||
fn f64_abs() {
|
fn f64_abs() {
|
||||||
assert_evals_to!("Num.abs -4.7", 4.7, f64);
|
assert_evals_to!("Num.abs -4.7", 4.7, f64);
|
||||||
assert_evals_to!("Num.abs 5.8", 5.8, f64);
|
assert_evals_to!("Num.abs 5.8", 5.8, f64);
|
||||||
|
@ -539,7 +539,7 @@ fn f64_abs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn i64_abs() {
|
fn i64_abs() {
|
||||||
assert_evals_to!("Num.abs -6", 6, i64);
|
assert_evals_to!("Num.abs -6", 6, i64);
|
||||||
assert_evals_to!("Num.abs 7", 7, i64);
|
assert_evals_to!("Num.abs 7", 7, i64);
|
||||||
|
@ -713,7 +713,7 @@ fn gen_int_eq() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn gen_int_neq() {
|
fn gen_int_neq() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
|
@ -767,7 +767,7 @@ fn gen_dec_neq() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn gen_wrap_int_neq() {
|
fn gen_wrap_int_neq() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
|
@ -950,14 +950,14 @@ fn gen_rem_div_by_zero_i64() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn gen_is_zero_i64() {
|
fn gen_is_zero_i64() {
|
||||||
assert_evals_to!("Num.isZero 0", true, bool);
|
assert_evals_to!("Num.isZero 0", true, bool);
|
||||||
assert_evals_to!("Num.isZero 1", false, bool);
|
assert_evals_to!("Num.isZero 1", false, bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn gen_is_positive_i64() {
|
fn gen_is_positive_i64() {
|
||||||
assert_evals_to!("Num.isPositive 0", false, bool);
|
assert_evals_to!("Num.isPositive 0", false, bool);
|
||||||
assert_evals_to!("Num.isPositive 1", true, bool);
|
assert_evals_to!("Num.isPositive 1", true, bool);
|
||||||
|
@ -965,7 +965,7 @@ fn gen_is_positive_i64() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn gen_is_negative_i64() {
|
fn gen_is_negative_i64() {
|
||||||
assert_evals_to!("Num.isNegative 0", false, bool);
|
assert_evals_to!("Num.isNegative 0", false, bool);
|
||||||
assert_evals_to!("Num.isNegative 3", false, bool);
|
assert_evals_to!("Num.isNegative 3", false, bool);
|
||||||
|
@ -973,7 +973,7 @@ fn gen_is_negative_i64() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn gen_is_positive_f64() {
|
fn gen_is_positive_f64() {
|
||||||
assert_evals_to!("Num.isPositive 0.0", false, bool);
|
assert_evals_to!("Num.isPositive 0.0", false, bool);
|
||||||
assert_evals_to!("Num.isPositive 4.7", true, bool);
|
assert_evals_to!("Num.isPositive 4.7", true, bool);
|
||||||
|
@ -981,7 +981,7 @@ fn gen_is_positive_f64() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn gen_is_negative_f64() {
|
fn gen_is_negative_f64() {
|
||||||
assert_evals_to!("Num.isNegative 0.0", false, bool);
|
assert_evals_to!("Num.isNegative 0.0", false, bool);
|
||||||
assert_evals_to!("Num.isNegative 9.9", false, bool);
|
assert_evals_to!("Num.isNegative 9.9", false, bool);
|
||||||
|
@ -989,7 +989,7 @@ fn gen_is_negative_f64() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn gen_is_zero_f64() {
|
fn gen_is_zero_f64() {
|
||||||
assert_evals_to!("Num.isZero 0", true, bool);
|
assert_evals_to!("Num.isZero 0", true, bool);
|
||||||
assert_evals_to!("Num.isZero 0_0", true, bool);
|
assert_evals_to!("Num.isZero 0_0", true, bool);
|
||||||
|
@ -998,14 +998,14 @@ fn gen_is_zero_f64() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn gen_is_odd() {
|
fn gen_is_odd() {
|
||||||
assert_evals_to!("Num.isOdd 4", false, bool);
|
assert_evals_to!("Num.isOdd 4", false, bool);
|
||||||
assert_evals_to!("Num.isOdd 5", true, bool);
|
assert_evals_to!("Num.isOdd 5", true, bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn gen_is_even() {
|
fn gen_is_even() {
|
||||||
assert_evals_to!("Num.isEven 6", true, bool);
|
assert_evals_to!("Num.isEven 6", true, bool);
|
||||||
assert_evals_to!("Num.isEven 7", false, bool);
|
assert_evals_to!("Num.isEven 7", false, bool);
|
||||||
|
@ -1033,7 +1033,7 @@ fn tan() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn bitwise_and() {
|
fn bitwise_and() {
|
||||||
assert_evals_to!("Num.bitwiseAnd 20 20", 20, i64);
|
assert_evals_to!("Num.bitwiseAnd 20 20", 20, i64);
|
||||||
assert_evals_to!("Num.bitwiseAnd 25 10", 8, i64);
|
assert_evals_to!("Num.bitwiseAnd 25 10", 8, i64);
|
||||||
|
@ -1041,7 +1041,7 @@ fn bitwise_and() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn bitwise_xor() {
|
fn bitwise_xor() {
|
||||||
assert_evals_to!("Num.bitwiseXor 20 20", 0, i64);
|
assert_evals_to!("Num.bitwiseXor 20 20", 0, i64);
|
||||||
assert_evals_to!("Num.bitwiseXor 15 14", 1, i64);
|
assert_evals_to!("Num.bitwiseXor 15 14", 1, i64);
|
||||||
|
@ -1050,14 +1050,14 @@ fn bitwise_xor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn bitwise_or() {
|
fn bitwise_or() {
|
||||||
assert_evals_to!("Num.bitwiseOr 1 1", 1, i64);
|
assert_evals_to!("Num.bitwiseOr 1 1", 1, i64);
|
||||||
assert_evals_to!("Num.bitwiseOr 1 2", 3, i64);
|
assert_evals_to!("Num.bitwiseOr 1 2", 3, i64);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn lt_i64() {
|
fn lt_i64() {
|
||||||
assert_evals_to!("1 < 2", true, bool);
|
assert_evals_to!("1 < 2", true, bool);
|
||||||
assert_evals_to!("1 < 1", false, bool);
|
assert_evals_to!("1 < 1", false, bool);
|
||||||
|
@ -1066,7 +1066,7 @@ fn lt_i64() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn lte_i64() {
|
fn lte_i64() {
|
||||||
assert_evals_to!("1 <= 1", true, bool);
|
assert_evals_to!("1 <= 1", true, bool);
|
||||||
assert_evals_to!("2 <= 1", false, bool);
|
assert_evals_to!("2 <= 1", false, bool);
|
||||||
|
@ -1084,7 +1084,7 @@ fn gt_i64() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn gte_i64() {
|
fn gte_i64() {
|
||||||
assert_evals_to!("1 >= 1", true, bool);
|
assert_evals_to!("1 >= 1", true, bool);
|
||||||
assert_evals_to!("1 >= 2", false, bool);
|
assert_evals_to!("1 >= 2", false, bool);
|
||||||
|
@ -1093,7 +1093,7 @@ fn gte_i64() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn lt_f64() {
|
fn lt_f64() {
|
||||||
assert_evals_to!("1.1 < 1.2", true, bool);
|
assert_evals_to!("1.1 < 1.2", true, bool);
|
||||||
assert_evals_to!("1.1 < 1.1", false, bool);
|
assert_evals_to!("1.1 < 1.1", false, bool);
|
||||||
|
@ -1102,7 +1102,7 @@ fn lt_f64() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn lte_f64() {
|
fn lte_f64() {
|
||||||
assert_evals_to!("1.1 <= 1.1", true, bool);
|
assert_evals_to!("1.1 <= 1.1", true, bool);
|
||||||
assert_evals_to!("1.2 <= 1.1", false, bool);
|
assert_evals_to!("1.2 <= 1.1", false, bool);
|
||||||
|
@ -1120,7 +1120,7 @@ fn gt_f64() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn gte_f64() {
|
fn gte_f64() {
|
||||||
assert_evals_to!("1.1 >= 1.1", true, bool);
|
assert_evals_to!("1.1 >= 1.1", true, bool);
|
||||||
assert_evals_to!("1.1 >= 1.2", false, bool);
|
assert_evals_to!("1.1 >= 1.2", false, bool);
|
||||||
|
@ -1214,7 +1214,7 @@ fn tail_call_elimination() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-wasm"))]
|
||||||
fn int_negate() {
|
fn int_negate() {
|
||||||
assert_evals_to!("Num.neg 123", -123, i64);
|
assert_evals_to!("Num.neg 123", -123, i64);
|
||||||
assert_evals_to!("Num.neg Num.maxInt", -i64::MAX, i64);
|
assert_evals_to!("Num.neg Num.maxInt", -i64::MAX, i64);
|
||||||
|
@ -1272,19 +1272,19 @@ fn gen_basic_fn() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn int_to_float() {
|
fn int_to_float() {
|
||||||
assert_evals_to!("Num.toFloat 0x9", 9.0, f64);
|
assert_evals_to!("Num.toFloat 0x9", 9.0, f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn num_to_float() {
|
fn num_to_float() {
|
||||||
assert_evals_to!("Num.toFloat 9", 9.0, f64);
|
assert_evals_to!("Num.toFloat 9", 9.0, f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn float_to_float() {
|
fn float_to_float() {
|
||||||
assert_evals_to!("Num.toFloat 0.5", 0.5, f64);
|
assert_evals_to!("Num.toFloat 0.5", 0.5, f64);
|
||||||
}
|
}
|
||||||
|
@ -1312,13 +1312,13 @@ fn pow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn ceiling() {
|
fn ceiling() {
|
||||||
assert_evals_to!("Num.ceiling 1.1", 2, i64);
|
assert_evals_to!("Num.ceiling 1.1", 2, i64);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn floor() {
|
fn floor() {
|
||||||
assert_evals_to!("Num.floor 1.9", 1, i64);
|
assert_evals_to!("Num.floor 1.9", 1, i64);
|
||||||
}
|
}
|
||||||
|
@ -1379,7 +1379,7 @@ fn int_add_checked() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn int_add_wrap() {
|
fn int_add_wrap() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
|
@ -1483,7 +1483,7 @@ fn int_sub_overflow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn int_sub_wrap() {
|
fn int_sub_wrap() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
|
@ -1628,7 +1628,7 @@ fn float_negative_mul_overflow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn int_mul_wrap() {
|
fn int_mul_wrap() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
|
@ -1698,7 +1698,7 @@ fn float_mul_checked() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn shift_left_by() {
|
fn shift_left_by() {
|
||||||
assert_evals_to!("Num.shiftLeftBy 0 0b0000_0001", 0b0000_0001, i64);
|
assert_evals_to!("Num.shiftLeftBy 0 0b0000_0001", 0b0000_0001, i64);
|
||||||
assert_evals_to!("Num.shiftLeftBy 1 0b0000_0001", 0b0000_0010, i64);
|
assert_evals_to!("Num.shiftLeftBy 1 0b0000_0001", 0b0000_0010, i64);
|
||||||
|
@ -1706,7 +1706,7 @@ fn shift_left_by() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn shift_right_by() {
|
fn shift_right_by() {
|
||||||
// Sign Extended Right Shift
|
// Sign Extended Right Shift
|
||||||
|
@ -1716,7 +1716,7 @@ fn shift_right_by() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn shift_right_zf_by() {
|
fn shift_right_zf_by() {
|
||||||
// Logical Right Shift
|
// Logical Right Shift
|
||||||
|
@ -1921,7 +1921,7 @@ fn bytes_to_u32_random_u8s() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn when_on_i32() {
|
fn when_on_i32() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
|
@ -1944,7 +1944,7 @@ fn when_on_i32() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn when_on_i16() {
|
fn when_on_i16() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
|
|
|
@ -32,8 +32,6 @@ roc_unify = { path = "../compiler/unify" }
|
||||||
roc_reporting = { path = "../compiler/reporting" }
|
roc_reporting = { path = "../compiler/reporting" }
|
||||||
roc_solve = { path = "../compiler/solve" }
|
roc_solve = { path = "../compiler/solve" }
|
||||||
ven_graph = { path = "../vendor/pathfinding" }
|
ven_graph = { path = "../vendor/pathfinding" }
|
||||||
im = "15.0.0"
|
|
||||||
im-rc = "15.0.0"
|
|
||||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
arraystring = "0.3.0"
|
arraystring = "0.3.0"
|
||||||
libc = "0.2.106"
|
libc = "0.2.106"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue