mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
Merge branch 'trunk' into wasm_arrays
This commit is contained in:
commit
c14b4b81e0
82 changed files with 1947 additions and 1315 deletions
|
@ -31,7 +31,7 @@ fn nat_alias() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn i128_signed_int_alias() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -115,7 +115,7 @@ fn i8_signed_int_alias() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn i128_hex_int_alias() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -741,7 +741,7 @@ fn gen_int_less_than() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn gen_dec_eq() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -761,7 +761,7 @@ fn gen_dec_eq() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn gen_dec_neq() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -864,7 +864,7 @@ fn gen_sub_i64() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn gen_mul_dec() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1309,7 +1309,7 @@ fn num_to_float() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-dev"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
||||
fn num_to_float_f64_to_f32() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1328,7 +1328,47 @@ fn num_to_float_f64_to_f32() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-wasm", feature = "gen-dev"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
||||
fn num_to_float_f32_to_f32() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
|
||||
arg : F32
|
||||
arg = 9.0
|
||||
|
||||
ret : F32
|
||||
ret = Num.toFloat arg
|
||||
ret
|
||||
"#
|
||||
),
|
||||
9.0,
|
||||
f32
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn num_to_float_f64_to_f64() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
|
||||
arg : F64
|
||||
arg = 9.0
|
||||
|
||||
ret : F64
|
||||
ret = Num.toFloat arg
|
||||
ret
|
||||
"#
|
||||
),
|
||||
9.0,
|
||||
f64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn num_to_float_f32_to_f64() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1790,7 +1830,7 @@ fn shift_right_zf_by() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn max_i128() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
|
|
@ -806,6 +806,24 @@ fn return_nested_record() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn nested_record_load() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
x = { a : { b : 0x5 } }
|
||||
|
||||
y = x.a
|
||||
|
||||
y.b
|
||||
"#
|
||||
),
|
||||
5,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn accessor_twice() {
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
#![cfg(feature = "gen-llvm")]
|
||||
|
||||
#[cfg(feature = "gen-llvm")]
|
||||
use crate::helpers::llvm::assert_evals_to;
|
||||
|
||||
// #[cfg(feature = "gen-dev")]
|
||||
// use crate::helpers::dev::assert_evals_to;
|
||||
|
||||
// #[cfg(feature = "gen-wasm")]
|
||||
// use crate::helpers::wasm::assert_evals_to;
|
||||
#[cfg(feature = "gen-wasm")]
|
||||
use crate::helpers::wasm::assert_evals_to;
|
||||
|
||||
// use crate::assert_wasm_evals_to as assert_evals_to;
|
||||
#[allow(unused_imports)]
|
||||
use indoc::indoc;
|
||||
#[allow(unused_imports)]
|
||||
use roc_std::{RocList, RocStr};
|
||||
|
||||
#[test]
|
||||
|
@ -31,7 +31,7 @@ fn width_and_alignment_u8_u8() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn applied_tag_nothing_ir() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -51,7 +51,7 @@ fn applied_tag_nothing_ir() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn applied_tag_nothing() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -71,7 +71,7 @@ fn applied_tag_nothing() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn applied_tag_just() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -90,7 +90,7 @@ fn applied_tag_just() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn applied_tag_just_ir() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -109,7 +109,7 @@ fn applied_tag_just_ir() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn applied_tag_just_enum() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -133,7 +133,7 @@ fn applied_tag_just_enum() {
|
|||
}
|
||||
|
||||
// #[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
// #[cfg(any(feature = "gen-llvm"))]
|
||||
// fn raw_result() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
|
@ -149,7 +149,7 @@ fn applied_tag_just_enum() {
|
|||
// );
|
||||
// }
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn true_is_true() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -166,7 +166,7 @@ fn true_is_true() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn false_is_false() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -205,7 +205,7 @@ fn basic_enum() {
|
|||
}
|
||||
|
||||
// #[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
// #[cfg(any(feature = "gen-llvm"))]
|
||||
// fn linked_list_empty() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
|
@ -224,7 +224,7 @@ fn basic_enum() {
|
|||
// }
|
||||
//
|
||||
// #[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
// #[cfg(any(feature = "gen-llvm"))]
|
||||
// fn linked_list_singleton() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
|
@ -243,7 +243,7 @@ fn basic_enum() {
|
|||
// }
|
||||
//
|
||||
// #[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
// #[cfg(any(feature = "gen-llvm"))]
|
||||
// fn linked_list_is_empty() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
|
@ -264,7 +264,7 @@ fn basic_enum() {
|
|||
// );
|
||||
// }
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn even_odd() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -290,7 +290,7 @@ fn even_odd() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn gen_literal_true() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -304,7 +304,7 @@ fn gen_literal_true() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn gen_if_float() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -317,7 +317,7 @@ fn gen_if_float() {
|
|||
);
|
||||
}
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn when_on_nothing() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -336,7 +336,7 @@ fn when_on_nothing() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn when_on_just() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -355,7 +355,7 @@ fn when_on_just() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn when_on_result() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -374,7 +374,7 @@ fn when_on_result() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn when_on_these() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -396,7 +396,7 @@ fn when_on_these() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn match_on_two_values() {
|
||||
// this will produce a Chain internally
|
||||
assert_evals_to!(
|
||||
|
@ -413,8 +413,8 @@ fn match_on_two_values() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn pair_with_guard_pattern() {
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn pair_with_underscore() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
|
@ -430,8 +430,8 @@ fn pair_with_guard_pattern() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn result_with_guard_pattern() {
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn result_with_underscore() {
|
||||
// This test revealed an issue with hashing Test values
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -451,7 +451,7 @@ fn result_with_guard_pattern() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn maybe_is_just_not_nested() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -476,7 +476,7 @@ fn maybe_is_just_not_nested() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn maybe_is_just_nested() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -498,7 +498,7 @@ fn maybe_is_just_nested() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn nested_pattern_match() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -535,7 +535,7 @@ fn if_guard_vanilla() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[ignore]
|
||||
fn when_on_single_value_tag() {
|
||||
// this fails because the switched-on symbol is not defined
|
||||
|
@ -711,7 +711,7 @@ fn if_guard_exhaustiveness() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn when_on_enum() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -733,7 +733,7 @@ fn when_on_enum() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn pattern_matching_unit() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -792,7 +792,7 @@ fn pattern_matching_unit() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn one_element_tag() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -809,7 +809,7 @@ fn one_element_tag() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn nested_tag_union() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -830,7 +830,7 @@ fn nested_tag_union() {
|
|||
);
|
||||
}
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn unit_type() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -849,25 +849,7 @@ fn unit_type() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn nested_record_load() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
x = { a : { b : 0x5 } }
|
||||
|
||||
y = x.a
|
||||
|
||||
y.b
|
||||
"#
|
||||
),
|
||||
5,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn join_point_if() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -884,7 +866,7 @@ fn join_point_if() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn join_point_when() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -910,7 +892,7 @@ fn join_point_when() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn join_point_with_cond_expr() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -949,7 +931,7 @@ fn join_point_with_cond_expr() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn alignment_in_single_tag_construction() {
|
||||
assert_evals_to!(indoc!("Three (1 == 1) 32"), (32i64, true), (i64, bool));
|
||||
|
||||
|
@ -961,7 +943,7 @@ fn alignment_in_single_tag_construction() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn alignment_in_single_tag_pattern_match() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -993,7 +975,7 @@ fn alignment_in_single_tag_pattern_match() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn alignment_in_multi_tag_construction_two() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1011,7 +993,7 @@ fn alignment_in_multi_tag_construction_two() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn alignment_in_multi_tag_construction_three() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1028,7 +1010,7 @@ fn alignment_in_multi_tag_construction_three() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn alignment_in_multi_tag_pattern_match() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1067,7 +1049,7 @@ fn alignment_in_multi_tag_pattern_match() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[ignore]
|
||||
fn phantom_polymorphic() {
|
||||
// see https://github.com/rtfeldman/roc/issues/786 and below
|
||||
|
@ -1093,7 +1075,7 @@ fn phantom_polymorphic() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[ignore]
|
||||
fn phantom_polymorphic_record() {
|
||||
// see https://github.com/rtfeldman/roc/issues/786
|
||||
|
@ -1143,7 +1125,7 @@ fn result_never() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn nested_recursive_literal() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1248,7 +1230,7 @@ fn applied_tag_function_linked_list() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[should_panic(expected = "")]
|
||||
fn tag_must_be_its_own_type() {
|
||||
assert_evals_to!(
|
||||
|
|
7
compiler/test_gen/src/helpers/dummy_libc_program.c
Normal file
7
compiler/test_gen/src/helpers/dummy_libc_program.c
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include <stdio.h>
|
||||
|
||||
void main() {
|
||||
printf("Hello, I am a C program and I use libc.\n");
|
||||
printf("If you compile me, you'll compile libc too. That's handy for cross-compilation including Wasm.\n");
|
||||
printf("Use `zig build-exe` with `--global-cache-dir my/build/directory` to put libc.a where you want it.\n");
|
||||
}
|
|
@ -27,7 +27,7 @@ macro_rules! from_wasm_memory_primitive_decode {
|
|||
let raw_ptr = ptr as *mut u8;
|
||||
let slice = unsafe { std::slice::from_raw_parts_mut(raw_ptr, width) };
|
||||
|
||||
let ptr: wasmer::WasmPtr<u8, wasmer::Array> = wasmer::WasmPtr::new(offset as u32);
|
||||
let ptr: wasmer::WasmPtr<u8, wasmer::Array> = wasmer::WasmPtr::new(offset);
|
||||
let foobar = (ptr.deref(memory, 0, width as u32)).unwrap();
|
||||
let wasm_slice = unsafe { std::mem::transmute(foobar) };
|
||||
|
||||
|
|
|
@ -1,31 +1,27 @@
|
|||
use bumpalo::collections::vec::Vec;
|
||||
use bumpalo::Bump;
|
||||
use std::cell::Cell;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::marker::PhantomData;
|
||||
use tempfile::{tempdir, TempDir};
|
||||
use wasmer::Memory;
|
||||
|
||||
use crate::helpers::from_wasm32_memory::FromWasm32Memory;
|
||||
use crate::helpers::wasm32_test_result::Wasm32TestResult;
|
||||
use roc_builtins::bitcode;
|
||||
use roc_can::builtins::builtin_defs_map;
|
||||
use roc_collections::all::{MutMap, MutSet};
|
||||
use roc_gen_wasm::wasm_module::linking::{WasmObjectSymbol, WASM_SYM_UNDEFINED};
|
||||
use roc_gen_wasm::wasm_module::sections::{Import, ImportDesc};
|
||||
use roc_gen_wasm::wasm_module::{
|
||||
CodeBuilder, Export, ExportType, LocalId, Signature, SymInfo, ValueType, WasmModule,
|
||||
};
|
||||
use roc_gen_wasm::MEMORY_NAME;
|
||||
|
||||
// Should manually match build.rs
|
||||
const PLATFORM_FILENAME: &str = "wasm_test_platform";
|
||||
const OUT_DIR_VAR: &str = "TEST_GEN_OUT";
|
||||
const LIBC_PATH_VAR: &str = "TEST_GEN_WASM_LIBC_PATH";
|
||||
const COMPILER_RT_PATH_VAR: &str = "TEST_GEN_WASM_COMPILER_RT_PATH";
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use roc_mono::ir::PRETTY_PRINT_IR_SYMBOLS;
|
||||
|
||||
const TEST_WRAPPER_NAME: &str = "test_wrapper";
|
||||
|
||||
std::thread_local! {
|
||||
static TEST_COUNTER: Cell<u32> = Cell::new(0);
|
||||
}
|
||||
|
||||
fn promote_expr_to_module(src: &str) -> String {
|
||||
let mut buffer = String::from("app \"test\" provides [ main ] to \"./platform\"\n\nmain =\n");
|
||||
|
||||
|
@ -44,7 +40,7 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>(
|
|||
arena: &'a bumpalo::Bump,
|
||||
src: &str,
|
||||
stdlib: &'a roc_builtins::std::StdLib,
|
||||
_result_type_dummy: &T,
|
||||
_result_type_dummy: PhantomData<T>,
|
||||
) -> wasmer::Instance {
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
|
@ -124,9 +120,6 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>(
|
|||
|
||||
T::insert_test_wrapper(arena, &mut wasm_module, TEST_WRAPPER_NAME, main_fn_index);
|
||||
|
||||
// We can either generate the test platform or write an external source file, whatever works
|
||||
generate_test_platform(&mut wasm_module, arena);
|
||||
|
||||
let mut module_bytes = std::vec::Vec::with_capacity(4096);
|
||||
wasm_module.serialize_mut(&mut module_bytes);
|
||||
|
||||
|
@ -136,14 +129,14 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>(
|
|||
|
||||
let store = Store::default();
|
||||
|
||||
// Keep the final .wasm file for debugging with wasm-objdump or wasm2wat
|
||||
const DEBUG_WASM_FILE: bool = false;
|
||||
// Keep the output binary for debugging with wasm2wat, wasm-objdump, wasm-validate, wasmer...
|
||||
const KEEP_WASM_FILE: bool = false;
|
||||
|
||||
let wasmer_module = {
|
||||
let tmp_dir: TempDir; // directory for normal test runs, deleted when dropped
|
||||
let debug_dir: String; // persistent directory for debugging
|
||||
|
||||
let wasm_build_dir: &Path = if DEBUG_WASM_FILE {
|
||||
let wasm_build_dir: &Path = if KEEP_WASM_FILE {
|
||||
// Directory name based on a hash of the Roc source
|
||||
let mut hash_state = DefaultHasher::new();
|
||||
src.hash(&mut hash_state);
|
||||
|
@ -162,7 +155,10 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>(
|
|||
|
||||
let final_wasm_file = wasm_build_dir.join("final.wasm");
|
||||
let app_o_file = wasm_build_dir.join("app.o");
|
||||
let libc_a_file = "../gen_wasm/lib/libc.a";
|
||||
let test_out_dir = std::env::var(OUT_DIR_VAR).unwrap();
|
||||
let test_platform_o = format!("{}/{}.o", test_out_dir, PLATFORM_FILENAME);
|
||||
let libc_a_file = std::env::var(LIBC_PATH_VAR).unwrap();
|
||||
let compiler_rt_o_file = std::env::var(COMPILER_RT_PATH_VAR).unwrap();
|
||||
|
||||
// write the module to a file so the linker can access it
|
||||
std::fs::write(&app_o_file, &module_bytes).unwrap();
|
||||
|
@ -172,7 +168,9 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>(
|
|||
// input files
|
||||
app_o_file.to_str().unwrap(),
|
||||
bitcode::BUILTINS_WASM32_OBJ_PATH,
|
||||
libc_a_file,
|
||||
&test_platform_o,
|
||||
&libc_a_file,
|
||||
&compiler_rt_o_file,
|
||||
// output
|
||||
"-o",
|
||||
final_wasm_file.to_str().unwrap(),
|
||||
|
@ -221,7 +219,7 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>(
|
|||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn assert_wasm_evals_to_help<T>(src: &str, expected: T) -> Result<T, String>
|
||||
pub fn assert_wasm_evals_to_help<T>(src: &str, phantom: PhantomData<T>) -> Result<T, String>
|
||||
where
|
||||
T: FromWasm32Memory + Wasm32TestResult,
|
||||
{
|
||||
|
@ -230,7 +228,7 @@ where
|
|||
// NOTE the stdlib must be in the arena; just taking a reference will segfault
|
||||
let stdlib = arena.alloc(roc_builtins::std::standard_stdlib());
|
||||
|
||||
let instance = crate::helpers::wasm::helper_wasm(&arena, src, stdlib, &expected);
|
||||
let instance = crate::helpers::wasm::helper_wasm(&arena, src, stdlib, phantom);
|
||||
|
||||
let memory = instance.exports.get_memory(MEMORY_NAME).unwrap();
|
||||
|
||||
|
@ -244,6 +242,16 @@ where
|
|||
_ => panic!(),
|
||||
};
|
||||
|
||||
if false {
|
||||
println!("test_wrapper returned 0x{:x}", address);
|
||||
println!("Stack:");
|
||||
crate::helpers::wasm::debug_memory_hex(memory, address, std::mem::size_of::<T>());
|
||||
}
|
||||
if false {
|
||||
println!("Heap:");
|
||||
// Manually provide address and size based on printf in wasm_test_platform.c
|
||||
crate::helpers::wasm::debug_memory_hex(memory, 0x11440, 24);
|
||||
}
|
||||
let output = <T as FromWasm32Memory>::decode(memory, address as u32);
|
||||
|
||||
Ok(output)
|
||||
|
@ -251,10 +259,41 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Print out hex bytes of the test result, and a few words on either side
|
||||
/// Can be handy for debugging misalignment issues etc.
|
||||
pub fn debug_memory_hex(memory: &Memory, address: i32, size: usize) {
|
||||
let memory_words: &[u32] = unsafe {
|
||||
let memory_bytes = memory.data_unchecked();
|
||||
std::mem::transmute(memory_bytes)
|
||||
};
|
||||
|
||||
let extra_words = 2;
|
||||
let result_start = (address as usize) / 4;
|
||||
let result_end = result_start + ((size + 3) / 4);
|
||||
let start = result_start - extra_words;
|
||||
let end = result_end + extra_words;
|
||||
|
||||
for index in start..end {
|
||||
let result_marker = if index >= result_start && index < result_end {
|
||||
"|"
|
||||
} else {
|
||||
" "
|
||||
};
|
||||
println!(
|
||||
"{:x} {} {:08x}",
|
||||
index * 4,
|
||||
result_marker,
|
||||
memory_words[index]
|
||||
);
|
||||
}
|
||||
println!();
|
||||
}
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! assert_wasm_evals_to {
|
||||
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
|
||||
match $crate::helpers::wasm::assert_wasm_evals_to_help::<$ty>($src, $expected) {
|
||||
let phantom = std::marker::PhantomData;
|
||||
match $crate::helpers::wasm::assert_wasm_evals_to_help::<$ty>($src, phantom) {
|
||||
Err(msg) => panic!("{:?}", msg),
|
||||
Ok(actual) => {
|
||||
assert_eq!($transform(actual), $expected)
|
||||
|
@ -298,123 +337,3 @@ pub fn identity<T>(value: T) -> T {
|
|||
pub(crate) use assert_evals_to;
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use assert_wasm_evals_to;
|
||||
|
||||
fn wrap_libc_fn<'a>(
|
||||
module: &mut WasmModule<'a>,
|
||||
arena: &'a Bump,
|
||||
roc_name: &'a str,
|
||||
libc_name: &'a str,
|
||||
params: &'a [(ValueType, bool)],
|
||||
ret_type: Option<ValueType>,
|
||||
) {
|
||||
let symbol_table = module.linking.symbol_table_mut();
|
||||
|
||||
// Type signatures
|
||||
let mut wrapper_signature = Signature {
|
||||
param_types: Vec::with_capacity_in(params.len(), arena),
|
||||
ret_type,
|
||||
};
|
||||
let mut libc_signature = Signature {
|
||||
param_types: Vec::with_capacity_in(params.len(), arena),
|
||||
ret_type,
|
||||
};
|
||||
for (ty, used) in params.iter() {
|
||||
wrapper_signature.param_types.push(*ty);
|
||||
if *used {
|
||||
libc_signature.param_types.push(*ty);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Import a function from libc
|
||||
*/
|
||||
let libc_signature_index = module.types.insert(libc_signature);
|
||||
|
||||
// Import
|
||||
let import_index = module.import.entries.len() as u32;
|
||||
module.import.entries.push(Import {
|
||||
module: "env",
|
||||
name: libc_name.to_string(),
|
||||
description: ImportDesc::Func {
|
||||
signature_index: libc_signature_index,
|
||||
},
|
||||
});
|
||||
|
||||
// Linker info
|
||||
let libc_sym_idx = symbol_table.len() as u32;
|
||||
symbol_table.push(SymInfo::Function(WasmObjectSymbol::Imported {
|
||||
flags: WASM_SYM_UNDEFINED,
|
||||
index: import_index,
|
||||
}));
|
||||
|
||||
/*
|
||||
* Export a wrapper function
|
||||
*/
|
||||
|
||||
// Declaration
|
||||
let wrapper_sig_index = module.types.insert(wrapper_signature);
|
||||
module.function.signature_indices.push(wrapper_sig_index);
|
||||
|
||||
// Body
|
||||
let mut code_builder = CodeBuilder::new(arena);
|
||||
let mut num_libc_args = 0;
|
||||
for (i, (_, used)) in params.iter().enumerate() {
|
||||
if *used {
|
||||
code_builder.get_local(LocalId(i as u32));
|
||||
num_libc_args += 1;
|
||||
}
|
||||
}
|
||||
code_builder.call(
|
||||
import_index,
|
||||
libc_sym_idx,
|
||||
num_libc_args,
|
||||
ret_type.is_some(),
|
||||
);
|
||||
code_builder.build_fn_header(&[], 0, None);
|
||||
let wrapper_index = module.code.code_builders.len() as u32;
|
||||
module.code.code_builders.push(code_builder);
|
||||
|
||||
// Export
|
||||
module.export.entries.push(Export {
|
||||
name: roc_name.to_string(),
|
||||
ty: ExportType::Func,
|
||||
index: wrapper_index,
|
||||
});
|
||||
|
||||
// Linker symbol
|
||||
symbol_table.push(SymInfo::Function(WasmObjectSymbol::Defined {
|
||||
flags: 0,
|
||||
index: wrapper_index,
|
||||
name: roc_name.to_string(),
|
||||
}));
|
||||
}
|
||||
|
||||
fn generate_test_platform<'a>(module: &mut WasmModule<'a>, arena: &'a Bump) {
|
||||
use ValueType::I32;
|
||||
|
||||
wrap_libc_fn(
|
||||
module,
|
||||
arena,
|
||||
"roc_alloc",
|
||||
"malloc",
|
||||
// only the first argument of roc_alloc is passed to malloc
|
||||
&[(I32, true), (I32, false)],
|
||||
Some(I32),
|
||||
);
|
||||
wrap_libc_fn(
|
||||
module,
|
||||
arena,
|
||||
"roc_dealloc",
|
||||
"free",
|
||||
&[(I32, true), (I32, false)],
|
||||
None,
|
||||
);
|
||||
wrap_libc_fn(
|
||||
module,
|
||||
arena,
|
||||
"roc_realloc",
|
||||
"realloc",
|
||||
&[(I32, true), (I32, false), (I32, true), (I32, false)],
|
||||
Some(I32),
|
||||
);
|
||||
}
|
||||
|
|
64
compiler/test_gen/src/helpers/wasm_test_platform.c
Normal file
64
compiler/test_gen/src/helpers/wasm_test_platform.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
#include <stdio.h>
|
||||
|
||||
// If any printf is included for compilation, even if unused, test runs take 50% longer
|
||||
#define DEBUG 0
|
||||
|
||||
//--------------------------
|
||||
|
||||
void *roc_alloc(size_t size, unsigned int alignment)
|
||||
{
|
||||
void *allocated = malloc(size);
|
||||
#if DEBUG
|
||||
if (!allocated)
|
||||
{
|
||||
fprintf(stderr, "roc_alloc failed\n");
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("roc_alloc allocated %d bytes at %p\n", size, allocated);
|
||||
}
|
||||
#endif
|
||||
return allocated;
|
||||
}
|
||||
|
||||
//--------------------------
|
||||
|
||||
void *roc_realloc(void *ptr, size_t new_size, size_t old_size,
|
||||
unsigned int alignment)
|
||||
{
|
||||
return realloc(ptr, new_size);
|
||||
}
|
||||
|
||||
//--------------------------
|
||||
|
||||
void roc_dealloc(void *ptr, unsigned int alignment)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
//--------------------------
|
||||
|
||||
void roc_panic(void *ptr, unsigned int alignment)
|
||||
{
|
||||
#if DEBUG
|
||||
char *msg = (char *)ptr;
|
||||
fprintf(stderr,
|
||||
"Application crashed with message\n\n %s\n\nShutting down\n", msg);
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//--------------------------
|
||||
|
||||
void *roc_memcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
return memcpy(dest, src, n);
|
||||
}
|
||||
|
||||
//--------------------------
|
||||
|
||||
void *roc_memset(void *str, int c, size_t n)
|
||||
{
|
||||
return memset(str, c, n);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue