mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-20 23:37:56 +03:00
Merge pull request #3434 from rtfeldman/wasm-last-few-builtins
Wasm: all MVP builtins implemented
This commit is contained in:
commit
7dcd5d297a
@ -36,7 +36,8 @@ pub enum ProcSource {
|
||||
Roc,
|
||||
Helper,
|
||||
/// Wrapper function for higher-order calls from Zig to Roc
|
||||
HigherOrderWrapper(usize),
|
||||
HigherOrderMapper(usize),
|
||||
HigherOrderCompare(usize),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -463,7 +464,7 @@ impl<'a> WasmBackend<'a> {
|
||||
self.module.names.append_function(wasm_fn_index, name);
|
||||
}
|
||||
|
||||
/// Build a wrapper around a Roc procedure so that it can be called from our higher-order Zig builtins.
|
||||
/// Build a wrapper around a Roc procedure so that it can be called from Zig builtins List.map*
|
||||
///
|
||||
/// The generic Zig code passes *pointers* to all of the argument values (e.g. on the heap in a List).
|
||||
/// Numbers up to 64 bits are passed by value, so we need to load them from the provided pointer.
|
||||
@ -471,7 +472,7 @@ impl<'a> WasmBackend<'a> {
|
||||
///
|
||||
/// NOTE: If the builtins expected the return pointer first and closure data last, we could eliminate the wrapper
|
||||
/// when all args are pass-by-reference and non-zero size. But currently we need it to swap those around.
|
||||
pub fn build_higher_order_wrapper(
|
||||
pub fn build_higher_order_mapper(
|
||||
&mut self,
|
||||
wrapper_lookup_idx: usize,
|
||||
inner_lookup_idx: usize,
|
||||
@ -515,44 +516,22 @@ impl<'a> WasmBackend<'a> {
|
||||
for (i, wrapper_arg) in wrapper_arg_layouts.iter().enumerate() {
|
||||
let is_closure_data = i == 0; // Skip closure data (first for wrapper, last for inner)
|
||||
let is_return_pointer = i == wrapper_arg_layouts.len() - 1; // Skip return pointer (may not be an arg for inner. And if it is, swaps from end to start)
|
||||
if is_closure_data || is_return_pointer || wrapper_arg.stack_size(TARGET_INFO) == 0 {
|
||||
if is_closure_data || is_return_pointer {
|
||||
continue;
|
||||
}
|
||||
n_inner_wasm_args += 1;
|
||||
|
||||
// Load wrapper argument. They're all pointers.
|
||||
self.code_builder.get_local(LocalId(i as u32));
|
||||
|
||||
// Dereference any primitive-valued arguments
|
||||
match wrapper_arg {
|
||||
Layout::Boxed(inner_arg) => match inner_arg {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8 | IntWidth::I8)) => {
|
||||
self.code_builder.i32_load8_u(Bytes1, 0);
|
||||
}
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U16 | IntWidth::I16)) => {
|
||||
self.code_builder.i32_load16_u(Bytes2, 0);
|
||||
}
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U32 | IntWidth::I32)) => {
|
||||
self.code_builder.i32_load(Bytes4, 0);
|
||||
}
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U64 | IntWidth::I64)) => {
|
||||
self.code_builder.i64_load(Bytes8, 0);
|
||||
}
|
||||
Layout::Builtin(Builtin::Float(FloatWidth::F32)) => {
|
||||
self.code_builder.f32_load(Bytes4, 0);
|
||||
}
|
||||
Layout::Builtin(Builtin::Float(FloatWidth::F64)) => {
|
||||
self.code_builder.f64_load(Bytes8, 0);
|
||||
}
|
||||
Layout::Builtin(Builtin::Bool) => {
|
||||
self.code_builder.i32_load8_u(Bytes1, 0);
|
||||
}
|
||||
_ => {
|
||||
// Any other layout is a pointer, which we've already loaded. Nothing to do!
|
||||
}
|
||||
},
|
||||
x => internal_error!("Higher-order wrapper: expected a Box layout, got {:?}", x),
|
||||
let inner_layout = match wrapper_arg {
|
||||
Layout::Boxed(inner) => inner,
|
||||
x => internal_error!("Expected a Boxed layout, got {:?}", x),
|
||||
};
|
||||
if inner_layout.stack_size(TARGET_INFO) == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Load the argument pointer. If it's a primitive value, dereference it too.
|
||||
n_inner_wasm_args += 1;
|
||||
self.code_builder.get_local(LocalId(i as u32));
|
||||
self.dereference_boxed_value(inner_layout);
|
||||
}
|
||||
|
||||
// If the inner function has closure data, it's the last arg of the inner fn
|
||||
@ -594,6 +573,90 @@ impl<'a> WasmBackend<'a> {
|
||||
self.reset();
|
||||
}
|
||||
|
||||
/// Build a wrapper around a Roc comparison proc so that it can be called from higher-order Zig builtins.
|
||||
/// Comparison procedure signature is: closure_data, a, b -> Order (u8)
|
||||
///
|
||||
/// The generic Zig code passes *pointers* to all of the argument values (e.g. on the heap in a List).
|
||||
/// Numbers up to 64 bits are passed by value, so we need to load them from the provided pointer.
|
||||
/// Everything else is passed by reference, so we can just pass the pointer through.
|
||||
pub fn build_higher_order_compare(
|
||||
&mut self,
|
||||
wrapper_lookup_idx: usize,
|
||||
inner_lookup_idx: usize,
|
||||
) {
|
||||
use ValueType::*;
|
||||
|
||||
let ProcLookupData {
|
||||
name: wrapper_name,
|
||||
layout: wrapper_proc_layout,
|
||||
..
|
||||
} = self.proc_lookup[wrapper_lookup_idx];
|
||||
let closure_data_layout = wrapper_proc_layout.arguments[0];
|
||||
let value_layout = wrapper_proc_layout.arguments[1];
|
||||
|
||||
let mut n_inner_args = 2;
|
||||
if closure_data_layout.stack_size(TARGET_INFO) > 0 {
|
||||
self.code_builder.get_local(LocalId(0));
|
||||
n_inner_args += 1;
|
||||
}
|
||||
|
||||
let inner_layout = match value_layout {
|
||||
Layout::Boxed(inner) => inner,
|
||||
x => internal_error!("Expected a Boxed layout, got {:?}", x),
|
||||
};
|
||||
self.code_builder.get_local(LocalId(1));
|
||||
self.dereference_boxed_value(inner_layout);
|
||||
self.code_builder.get_local(LocalId(2));
|
||||
self.dereference_boxed_value(inner_layout);
|
||||
|
||||
// Call the wrapped inner function
|
||||
let inner_wasm_fn_index = self.fn_index_offset + inner_lookup_idx as u32;
|
||||
self.code_builder
|
||||
.call(inner_wasm_fn_index, n_inner_args, true);
|
||||
|
||||
// Write empty function header (local variables array with zero length)
|
||||
self.code_builder.build_fn_header_and_footer(&[], 0, None);
|
||||
|
||||
self.module.add_function_signature(Signature {
|
||||
param_types: bumpalo::vec![in self.env.arena; I32; 3],
|
||||
ret_type: Some(ValueType::I32),
|
||||
});
|
||||
|
||||
self.append_proc_debug_name(wrapper_name);
|
||||
self.reset();
|
||||
}
|
||||
|
||||
fn dereference_boxed_value(&mut self, inner: &Layout) {
|
||||
use Align::*;
|
||||
|
||||
match inner {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8 | IntWidth::I8)) => {
|
||||
self.code_builder.i32_load8_u(Bytes1, 0);
|
||||
}
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U16 | IntWidth::I16)) => {
|
||||
self.code_builder.i32_load16_u(Bytes2, 0);
|
||||
}
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U32 | IntWidth::I32)) => {
|
||||
self.code_builder.i32_load(Bytes4, 0);
|
||||
}
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U64 | IntWidth::I64)) => {
|
||||
self.code_builder.i64_load(Bytes8, 0);
|
||||
}
|
||||
Layout::Builtin(Builtin::Float(FloatWidth::F32)) => {
|
||||
self.code_builder.f32_load(Bytes4, 0);
|
||||
}
|
||||
Layout::Builtin(Builtin::Float(FloatWidth::F64)) => {
|
||||
self.code_builder.f64_load(Bytes8, 0);
|
||||
}
|
||||
Layout::Builtin(Builtin::Bool) => {
|
||||
self.code_builder.i32_load8_u(Bytes1, 0);
|
||||
}
|
||||
_ => {
|
||||
// Any other layout is a pointer, which we've already loaded. Nothing to do!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
|
||||
STATEMENTS
|
||||
|
@ -13,7 +13,6 @@ use bumpalo::collections::Vec;
|
||||
use bumpalo::{self, Bump};
|
||||
|
||||
use roc_collections::all::{MutMap, MutSet};
|
||||
use roc_module::low_level::LowLevelWrapperType;
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use roc_mono::code_gen_help::CodeGenHelp;
|
||||
use roc_mono::ir::{Proc, ProcLayout};
|
||||
@ -96,17 +95,10 @@ pub fn build_app_module<'a>(
|
||||
host_module.import.function_count() as u32 + host_module.code.preloaded_count;
|
||||
|
||||
// Pre-pass over the procedure names & layouts
|
||||
// Filter out procs we're going to inline & gather some data for lookups
|
||||
let mut fn_index: u32 = fn_index_offset;
|
||||
for ((sym, proc_layout), proc) in procedures.into_iter() {
|
||||
if matches!(
|
||||
LowLevelWrapperType::from_symbol(sym),
|
||||
LowLevelWrapperType::CanBeReplacedBy(_)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
// Create a lookup to tell us the final index of each proc in the output file
|
||||
for (i, ((sym, proc_layout), proc)) in procedures.into_iter().enumerate() {
|
||||
let fn_index = fn_index_offset + i as u32;
|
||||
procs.push(proc);
|
||||
|
||||
if env.exposed_to_host.contains(&sym) {
|
||||
maybe_main_fn_index = Some(fn_index);
|
||||
|
||||
@ -124,8 +116,6 @@ pub fn build_app_module<'a>(
|
||||
layout: proc_layout,
|
||||
source: ProcSource::Roc,
|
||||
});
|
||||
|
||||
fn_index += 1;
|
||||
}
|
||||
|
||||
let mut backend = WasmBackend::new(
|
||||
@ -179,7 +169,8 @@ pub fn build_app_module<'a>(
|
||||
match source {
|
||||
Roc => { /* already generated */ }
|
||||
Helper => backend.build_proc(helper_iter.next().unwrap()),
|
||||
HigherOrderWrapper(inner_idx) => backend.build_higher_order_wrapper(idx, *inner_idx),
|
||||
HigherOrderMapper(inner_idx) => backend.build_higher_order_mapper(idx, *inner_idx),
|
||||
HigherOrderCompare(inner_idx) => backend.build_higher_order_compare(idx, *inner_idx),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -530,7 +530,45 @@ impl<'a> LowLevelCall<'a> {
|
||||
|
||||
backend.call_host_fn_after_loading_args(bitcode::LIST_APPEND, 7, false);
|
||||
}
|
||||
ListPrepend => todo!("{:?}", self.lowlevel),
|
||||
ListPrepend => {
|
||||
// List.prepend : List elem, elem -> List elem
|
||||
|
||||
let list: Symbol = self.arguments[0];
|
||||
let elem: Symbol = self.arguments[1];
|
||||
|
||||
let elem_layout = unwrap_list_elem_layout(self.ret_layout);
|
||||
let (elem_width, elem_align) = elem_layout.stack_size_and_alignment(TARGET_INFO);
|
||||
let (elem_local, elem_offset, _) =
|
||||
ensure_symbol_is_in_memory(backend, elem, *elem_layout, backend.env.arena);
|
||||
|
||||
// Zig arguments Wasm types
|
||||
// (return pointer) i32
|
||||
// list: RocList i64, i32
|
||||
// alignment: u32 i32
|
||||
// element: Opaque i32
|
||||
// element_width: usize i32
|
||||
|
||||
// return pointer and list
|
||||
backend.storage.load_symbols_for_call(
|
||||
backend.env.arena,
|
||||
&mut backend.code_builder,
|
||||
&[list],
|
||||
self.ret_symbol,
|
||||
&WasmLayout::new(&self.ret_layout),
|
||||
CallConv::Zig,
|
||||
);
|
||||
|
||||
backend.code_builder.i32_const(elem_align as i32);
|
||||
|
||||
backend.code_builder.get_local(elem_local);
|
||||
if elem_offset > 0 {
|
||||
backend.code_builder.i32_const(elem_offset as i32);
|
||||
backend.code_builder.i32_add();
|
||||
}
|
||||
backend.code_builder.i32_const(elem_width as i32);
|
||||
|
||||
backend.call_host_fn_after_loading_args(bitcode::LIST_PREPEND, 6, false);
|
||||
}
|
||||
ListSublist => {
|
||||
// As a low-level, record is destructured
|
||||
// List.sublist : List elem, start : Nat, len : Nat -> List elem
|
||||
@ -1980,7 +2018,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
||||
|
||||
// We create a wrapper around the passed function, which just unboxes the arguments.
|
||||
// This allows Zig builtins to have a generic pointer-based interface.
|
||||
let source = {
|
||||
let helper_proc_source = {
|
||||
let passed_proc_layout = ProcLayout {
|
||||
arguments: argument_layouts,
|
||||
result: *result_layout,
|
||||
@ -1993,7 +2031,13 @@ pub fn call_higher_order_lowlevel<'a>(
|
||||
*name == fn_name.name() && layout == &passed_proc_layout
|
||||
})
|
||||
.unwrap();
|
||||
ProcSource::HigherOrderWrapper(passed_proc_index)
|
||||
match op {
|
||||
ListSortWith { .. } => ProcSource::HigherOrderCompare(passed_proc_index),
|
||||
ListMap { .. } | ListMap2 { .. } | ListMap3 { .. } | ListMap4 { .. } => {
|
||||
ProcSource::HigherOrderMapper(passed_proc_index)
|
||||
}
|
||||
DictWalk { .. } => todo!("DictWalk"),
|
||||
}
|
||||
};
|
||||
let wrapper_sym = backend.create_symbol(&format!("#wrap#{:?}", fn_name));
|
||||
let wrapper_layout = {
|
||||
@ -2013,16 +2057,30 @@ pub fn call_higher_order_lowlevel<'a>(
|
||||
.take(n_non_closure_args)
|
||||
.map(Layout::Boxed),
|
||||
);
|
||||
wrapper_arg_layouts.push(Layout::Boxed(result_layout));
|
||||
|
||||
ProcLayout {
|
||||
arguments: wrapper_arg_layouts.into_bump_slice(),
|
||||
result: Layout::UNIT,
|
||||
captures_niche: fn_name.captures_niche(),
|
||||
match helper_proc_source {
|
||||
ProcSource::HigherOrderMapper(_) => {
|
||||
// Our convention for mappers is that they write to the heap via the last argument
|
||||
wrapper_arg_layouts.push(Layout::Boxed(result_layout));
|
||||
ProcLayout {
|
||||
arguments: wrapper_arg_layouts.into_bump_slice(),
|
||||
result: Layout::UNIT,
|
||||
captures_niche: fn_name.captures_niche(),
|
||||
}
|
||||
}
|
||||
ProcSource::HigherOrderCompare(_) => ProcLayout {
|
||||
arguments: wrapper_arg_layouts.into_bump_slice(),
|
||||
result: *result_layout,
|
||||
captures_niche: fn_name.captures_niche(),
|
||||
},
|
||||
ProcSource::Roc | ProcSource::Helper => {
|
||||
internal_error!("Should never reach here for {:?}", helper_proc_source)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let wrapper_fn_idx = backend.register_helper_proc(wrapper_sym, wrapper_layout, source);
|
||||
let wrapper_fn_idx =
|
||||
backend.register_helper_proc(wrapper_sym, wrapper_layout, helper_proc_source);
|
||||
let wrapper_fn_ptr = backend.get_fn_ptr(wrapper_fn_idx);
|
||||
let inc_fn_ptr = match closure_data_layout {
|
||||
Layout::Struct {
|
||||
@ -2094,7 +2152,40 @@ pub fn call_higher_order_lowlevel<'a>(
|
||||
*owns_captured_environment,
|
||||
),
|
||||
|
||||
ListSortWith { .. } | DictWalk { .. } => todo!("{:?}", op),
|
||||
ListSortWith { xs } => {
|
||||
let elem_layout = unwrap_list_elem_layout(backend.storage.symbol_layouts[xs]);
|
||||
let (element_width, alignment) = elem_layout.stack_size_and_alignment(TARGET_INFO);
|
||||
|
||||
let cb = &mut backend.code_builder;
|
||||
|
||||
// (return pointer) i32
|
||||
// input: RocList, i64, i32
|
||||
// caller: CompareFn, i32
|
||||
// data: Opaque, i32
|
||||
// inc_n_data: IncN, i32
|
||||
// data_is_owned: bool, i32
|
||||
// alignment: u32, i32
|
||||
// element_width: usize, i32
|
||||
|
||||
backend.storage.load_symbols(cb, &[return_sym]);
|
||||
backend.storage.load_symbol_zig(cb, *xs);
|
||||
cb.i32_const(wrapper_fn_ptr);
|
||||
if closure_data_exists {
|
||||
backend.storage.load_symbols(cb, &[*captured_environment]);
|
||||
} else {
|
||||
// load_symbols assumes that a zero-size arg should be eliminated in code gen,
|
||||
// but that's a specialization that our Zig code doesn't have! Pass a null pointer.
|
||||
cb.i32_const(0);
|
||||
}
|
||||
cb.i32_const(inc_fn_ptr);
|
||||
cb.i32_const(*owns_captured_environment as i32);
|
||||
cb.i32_const(alignment as i32);
|
||||
cb.i32_const(element_width as i32);
|
||||
|
||||
backend.call_host_fn_after_loading_args(bitcode::LIST_SORT_WITH, 9, false);
|
||||
}
|
||||
|
||||
DictWalk { .. } => todo!("{:?}", op),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,6 +222,7 @@ impl<'a> Storage<'a> {
|
||||
arena: &'a Bump,
|
||||
) {
|
||||
let mut wide_number_args = Vec::with_capacity_in(args.len(), arena);
|
||||
let mut has_zero_size_arg = false;
|
||||
|
||||
for (layout, symbol) in args {
|
||||
self.symbol_layouts.insert(*symbol, *layout);
|
||||
@ -260,6 +261,7 @@ impl<'a> Storage<'a> {
|
||||
if size == 0 {
|
||||
// An argument with zero size is purely conceptual, and will not exist in Wasm.
|
||||
// However we need to track the symbol, so we treat it like a local variable.
|
||||
has_zero_size_arg = true;
|
||||
StackMemoryLocation::FrameOffset(0)
|
||||
} else {
|
||||
StackMemoryLocation::PointerArg(LocalId(local_index))
|
||||
@ -282,7 +284,7 @@ impl<'a> Storage<'a> {
|
||||
// If any arguments are 128-bit numbers, store them in the stack frame
|
||||
// This makes it easier to keep track of which symbols are on the Wasm value stack
|
||||
// The frame pointer will be the next local after the arguments
|
||||
if self.stack_frame_size > 0 {
|
||||
if self.stack_frame_size > 0 || has_zero_size_arg {
|
||||
let frame_ptr = LocalId(self.arg_types.len() as u32);
|
||||
self.stack_frame_pointer = Some(frame_ptr);
|
||||
self.local_types.push(PTR_TYPE);
|
||||
|
@ -14,7 +14,7 @@ use crate::wasm_module::{
|
||||
linking::SymInfo, linking::WasmObjectSymbol, Align, CodeBuilder, Export, ExportType, LocalId,
|
||||
Signature, ValueType, WasmModule,
|
||||
};
|
||||
use roc_std::{RocDec, RocList, RocOrder, RocStr};
|
||||
use roc_std::{RocDec, RocList, RocOrder, RocResult, RocStr};
|
||||
|
||||
/// Type-driven wrapper generation
|
||||
pub trait Wasm32Result {
|
||||
@ -200,6 +200,17 @@ impl<T: Wasm32Result> Wasm32Result for RocList<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Wasm32Sized, E: Wasm32Sized> Wasm32Result for RocResult<T, E> {
|
||||
fn build_wrapper_body(code_builder: &mut CodeBuilder, main_function_index: u32) {
|
||||
build_wrapper_body_stack_memory(
|
||||
code_builder,
|
||||
main_function_index,
|
||||
Ord::max(T::ACTUAL_WIDTH, E::ACTUAL_WIDTH)
|
||||
+ Ord::max(T::ALIGN_OF_WASM, E::ALIGN_OF_WASM),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Wasm32Result> Wasm32Result for &'_ T {
|
||||
build_wrapper_body_primitive!(i32_store, Align::Bytes4);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use roc_std::{RocDec, RocList, RocOrder, RocStr};
|
||||
use roc_std::{RocDec, RocList, RocOrder, RocResult, RocStr};
|
||||
|
||||
pub trait Wasm32Sized: Sized {
|
||||
const SIZE_OF_WASM: usize;
|
||||
@ -41,6 +41,11 @@ impl<T: Wasm32Sized> Wasm32Sized for RocList<T> {
|
||||
const ALIGN_OF_WASM: usize = 4;
|
||||
}
|
||||
|
||||
impl<T: Wasm32Sized, E: Wasm32Sized> Wasm32Sized for RocResult<T, E> {
|
||||
const ALIGN_OF_WASM: usize = max2(T::ALIGN_OF_WASM, E::ALIGN_OF_WASM);
|
||||
const SIZE_OF_WASM: usize = max2(T::ACTUAL_WIDTH, E::ACTUAL_WIDTH) + 1;
|
||||
}
|
||||
|
||||
impl<T: Wasm32Sized> Wasm32Sized for &'_ T {
|
||||
const SIZE_OF_WASM: usize = 4;
|
||||
const ALIGN_OF_WASM: usize = 4;
|
||||
|
@ -10,9 +10,9 @@ use crate::helpers::wasm::assert_evals_to;
|
||||
#[cfg(test)]
|
||||
use indoc::indoc;
|
||||
|
||||
#[cfg(all(test, feature = "gen-llvm"))]
|
||||
#[cfg(all(test, any(feature = "gen-llvm", feature = "gen-wasm")))]
|
||||
use roc_std::RocList;
|
||||
#[cfg(all(test, feature = "gen-llvm"))]
|
||||
#[cfg(all(test, any(feature = "gen-llvm", feature = "gen-wasm")))]
|
||||
use roc_std::RocStr;
|
||||
|
||||
#[test]
|
||||
@ -223,7 +223,7 @@ fn ability_used_as_type_still_compiles() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn encode() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -269,7 +269,7 @@ fn encode() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn decode() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -327,7 +327,7 @@ fn decode() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn encode_use_stdlib() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -307,8 +307,9 @@ fn list_split() {
|
||||
(RocList<i64>, RocList<i64>,)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_drop() {
|
||||
assert_evals_to!(
|
||||
"List.drop [1,2,3] 2",
|
||||
@ -353,7 +354,7 @@ fn list_drop_at() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_intersperse() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -398,7 +399,7 @@ fn list_drop_at_shared() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_drop_if_empty_list_of_int() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -415,7 +416,7 @@ fn list_drop_if_empty_list_of_int() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_drop_if_empty_list() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -432,7 +433,7 @@ fn list_drop_if_empty_list() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_drop_if_always_false_for_non_empty_list() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -446,7 +447,7 @@ fn list_drop_if_always_false_for_non_empty_list() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_drop_if_always_true_for_non_empty_list() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -460,7 +461,7 @@ fn list_drop_if_always_true_for_non_empty_list() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_drop_if_geq3() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -474,7 +475,7 @@ fn list_drop_if_geq3() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_drop_if_string_eq() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -488,7 +489,7 @@ fn list_drop_if_string_eq() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_drop_last() {
|
||||
assert_evals_to!(
|
||||
"List.dropLast [1, 2, 3]",
|
||||
@ -508,7 +509,7 @@ fn list_drop_last() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_drop_last_mutable() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -530,7 +531,7 @@ fn list_drop_last_mutable() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_drop_first() {
|
||||
assert_evals_to!(
|
||||
"List.dropFirst [1, 2, 3]",
|
||||
@ -630,7 +631,7 @@ fn list_append_longer_list() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_prepend() {
|
||||
assert_evals_to!("List.prepend [] 1", RocList::from_slice(&[1]), RocList<i64>);
|
||||
assert_evals_to!(
|
||||
@ -669,7 +670,7 @@ fn list_prepend() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_prepend_bools() {
|
||||
assert_evals_to!(
|
||||
"List.prepend [True, False] True",
|
||||
@ -679,7 +680,7 @@ fn list_prepend_bools() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_prepend_big_list() {
|
||||
assert_evals_to!(
|
||||
"List.prepend [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 100, 100, 100, 100] 9",
|
||||
@ -795,7 +796,7 @@ fn list_walk_until_sum() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_implements_position() {
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
@ -818,7 +819,7 @@ fn list_walk_implements_position() {
|
||||
Some v -> v
|
||||
"#,
|
||||
2,
|
||||
i64
|
||||
usize
|
||||
);
|
||||
}
|
||||
|
||||
@ -841,7 +842,7 @@ fn list_walk_until_even_prefix_sum() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_keep_if_empty_list_of_int() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -859,7 +860,7 @@ fn list_keep_if_empty_list_of_int() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_keep_if_empty_list() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -878,7 +879,7 @@ fn list_keep_if_empty_list() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_keep_if_always_true_for_non_empty_list() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -900,7 +901,7 @@ fn list_keep_if_always_true_for_non_empty_list() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_keep_if_always_false_for_non_empty_list() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -918,7 +919,7 @@ fn list_keep_if_always_false_for_non_empty_list() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_keep_if_one() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -936,7 +937,7 @@ fn list_keep_if_one() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_keep_if_str_is_hello() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -2289,7 +2290,7 @@ fn quicksort_singleton() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn empty_list_increment_decrement() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -2301,12 +2302,12 @@ fn empty_list_increment_decrement() {
|
||||
"#
|
||||
),
|
||||
0,
|
||||
i64
|
||||
usize
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_literal_increment_decrement() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -2318,7 +2319,7 @@ fn list_literal_increment_decrement() {
|
||||
"#
|
||||
),
|
||||
6,
|
||||
i64
|
||||
usize
|
||||
);
|
||||
}
|
||||
|
||||
@ -2496,7 +2497,7 @@ fn list_product() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_keep_void() {
|
||||
assert_evals_to!(
|
||||
"List.keepOks [] (\\x -> x)",
|
||||
@ -2512,7 +2513,7 @@ fn list_keep_void() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_keep_oks() {
|
||||
assert_evals_to!(
|
||||
"List.keepOks [Ok {}, Ok {}] (\\x -> x)",
|
||||
@ -2537,7 +2538,7 @@ fn list_keep_oks() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_keep_errs() {
|
||||
assert_evals_to!(
|
||||
"List.keepErrs [Err {}, Err {}] (\\x -> x)",
|
||||
@ -2613,7 +2614,7 @@ fn list_range() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_sort_with() {
|
||||
assert_evals_to!(
|
||||
"List.sortWith [] Num.compare",
|
||||
@ -2633,7 +2634,7 @@ fn list_sort_with() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_sort_asc() {
|
||||
assert_evals_to!(
|
||||
"List.sortAsc []",
|
||||
@ -2648,7 +2649,7 @@ fn list_sort_asc() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_sort_desc() {
|
||||
assert_evals_to!(
|
||||
"List.sortDesc []",
|
||||
@ -2712,7 +2713,7 @@ fn list_all_empty_with_unknown_element_type() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[should_panic(expected = r#"Roc failed with message: "invalid ret_layout""#)]
|
||||
fn lists_with_incompatible_type_param_in_if() {
|
||||
assert_evals_to!(
|
||||
@ -2733,7 +2734,7 @@ fn lists_with_incompatible_type_param_in_if() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn map_with_index_multi_record() {
|
||||
// see https://github.com/rtfeldman/roc/issues/1700
|
||||
assert_evals_to!(
|
||||
@ -2777,7 +2778,7 @@ fn empty_list_of_function_type() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_join_map() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -2797,7 +2798,7 @@ fn list_join_map() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_join_map_empty() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -2874,7 +2875,7 @@ fn list_find_empty_layout() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_find_index() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -2885,12 +2886,12 @@ fn list_find_index() {
|
||||
"#
|
||||
),
|
||||
1,
|
||||
i64
|
||||
usize
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_find_index_not_found() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -2901,12 +2902,12 @@ fn list_find_index_not_found() {
|
||||
"#
|
||||
),
|
||||
999,
|
||||
i64
|
||||
usize
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_find_index_empty_typed_list() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -2917,12 +2918,12 @@ fn list_find_index_empty_typed_list() {
|
||||
"#
|
||||
),
|
||||
999,
|
||||
i64
|
||||
usize
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn monomorphized_lists() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -2936,7 +2937,7 @@ fn monomorphized_lists() {
|
||||
"#
|
||||
),
|
||||
18,
|
||||
u64
|
||||
usize
|
||||
)
|
||||
}
|
||||
|
||||
@ -2960,7 +2961,7 @@ fn with_capacity() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn call_function_in_empty_list() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -981,7 +981,7 @@ fn overflow_frees_list() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[should_panic(expected = "Roc failed with message: ")]
|
||||
fn undefined_variable() {
|
||||
assert_evals_to!(
|
||||
@ -999,7 +999,7 @@ fn undefined_variable() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[should_panic(expected = "Roc failed with message: ")]
|
||||
fn annotation_without_body() {
|
||||
assert_evals_to!(
|
||||
@ -1039,7 +1039,7 @@ fn simple_closure() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn nested_closure() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -1121,7 +1121,7 @@ fn specialize_closure() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn io_poc_effect() {
|
||||
assert_non_opt_evals_to!(
|
||||
indoc!(
|
||||
@ -1152,7 +1152,7 @@ fn io_poc_effect() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn io_poc_desugared() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -1374,7 +1374,7 @@ fn linked_list_singleton() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn recursive_function_with_rigid() {
|
||||
assert_non_opt_evals_to!(
|
||||
indoc!(
|
||||
@ -1401,7 +1401,7 @@ fn recursive_function_with_rigid() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn rbtree_insert() {
|
||||
assert_non_opt_evals_to!(
|
||||
indoc!(
|
||||
@ -2020,7 +2020,7 @@ fn hof_conditional() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[should_panic(
|
||||
expected = "Roc failed with message: \"Shadowing { original_region: @55-56, shadow: @88-89 Ident"
|
||||
)]
|
||||
@ -2497,7 +2497,7 @@ fn backpassing_result() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[should_panic(expected = "Shadowing { original_region: @55-56, shadow: @72-73 Ident")]
|
||||
fn function_malformed_pattern() {
|
||||
assert_evals_to!(
|
||||
@ -2589,7 +2589,7 @@ fn module_thunk_is_function() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[should_panic(expected = "Roc failed with message: ")]
|
||||
fn hit_unresolved_type_variable() {
|
||||
assert_evals_to!(
|
||||
@ -2732,7 +2732,7 @@ fn lambda_set_byte() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn lambda_set_struct_byte() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -2791,7 +2791,7 @@ fn lambda_set_enum_byte_byte() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_until() {
|
||||
// see https://github.com/rtfeldman/roc/issues/1576
|
||||
assert_evals_to!(
|
||||
@ -2872,7 +2872,7 @@ fn int_literal_not_specialized_no_annotation() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn unresolved_tvar_when_capture_is_unused() {
|
||||
// see https://github.com/rtfeldman/roc/issues/1585
|
||||
assert_evals_to!(
|
||||
@ -2899,7 +2899,7 @@ fn unresolved_tvar_when_capture_is_unused() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[should_panic(expected = "Roc failed with message: ")]
|
||||
fn value_not_exposed_hits_panic() {
|
||||
assert_evals_to!(
|
||||
@ -2969,7 +2969,7 @@ fn mix_function_and_closure_level_of_indirection() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg_attr(debug_assertions, ignore)] // this test stack-overflows the compiler in debug mode
|
||||
fn do_pass_bool_byte_closure_layout() {
|
||||
// see https://github.com/rtfeldman/roc/pull/1706
|
||||
@ -3172,7 +3172,7 @@ fn alias_defined_out_of_order() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn recursively_build_effect() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -3243,7 +3243,7 @@ fn polymophic_expression_captured_inside_closure() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn issue_2322() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -3481,7 +3481,7 @@ fn mutual_recursion_top_level_defs() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn polymorphic_lambda_captures_polymorphic_value() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -3500,7 +3500,7 @@ fn polymorphic_lambda_captures_polymorphic_value() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn lambda_capture_niche_u64_vs_u8_capture() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -3527,7 +3527,7 @@ fn lambda_capture_niche_u64_vs_u8_capture() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn lambda_capture_niches_with_other_lambda_capture() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -3560,7 +3560,7 @@ fn lambda_capture_niches_with_other_lambda_capture() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn lambda_capture_niches_with_non_capturing_function() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -3593,7 +3593,7 @@ fn lambda_capture_niches_with_non_capturing_function() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn lambda_capture_niches_have_captured_function_in_closure() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -224,7 +224,7 @@ fn is_err() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn roc_result_ok() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -241,7 +241,7 @@ fn roc_result_ok() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn roc_result_err() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -258,7 +258,7 @@ fn roc_result_err() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn issue_2583_specialize_errors_behind_unified_branches() {
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
|
@ -1182,7 +1182,7 @@ fn applied_tag_function() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn applied_tag_function_result() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -1221,7 +1221,7 @@ fn applied_tag_function_linked_list() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn applied_tag_function_pair() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -1260,7 +1260,7 @@ fn tag_must_be_its_own_type() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn recursive_tag_union_into_flat_tag_union() {
|
||||
// Comprehensive test for correctness in cli/tests/repl_eval
|
||||
assert_evals_to!(
|
||||
@ -1535,7 +1535,7 @@ fn issue_2458_deep_recursion_var() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn issue_1162() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -1705,7 +1705,7 @@ fn issue_2900_unreachable_pattern() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn issue_3261_non_nullable_unwrapped_recursive_union_at_index() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1,5 +1,5 @@
|
||||
use roc_gen_wasm::wasm32_sized::Wasm32Sized;
|
||||
use roc_std::{RocDec, RocList, RocOrder, RocStr};
|
||||
use roc_std::{RocDec, RocList, RocOrder, RocResult, RocStr};
|
||||
use std::convert::TryInto;
|
||||
|
||||
pub trait FromWasmerMemory: Wasm32Sized {
|
||||
@ -95,6 +95,22 @@ impl<T: FromWasmerMemory + Clone> FromWasmerMemory for RocList<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromWasmerMemory + Wasm32Sized, E: FromWasmerMemory + Wasm32Sized> FromWasmerMemory
|
||||
for RocResult<T, E>
|
||||
{
|
||||
fn decode(memory: &wasmer::Memory, offset: u32) -> Self {
|
||||
let tag_offset = Ord::max(T::ACTUAL_WIDTH, E::ACTUAL_WIDTH);
|
||||
let tag = <u8 as FromWasmerMemory>::decode(memory, offset + tag_offset as u32);
|
||||
if tag == 1 {
|
||||
let value = <T as FromWasmerMemory>::decode(memory, offset);
|
||||
RocResult::ok(value)
|
||||
} else {
|
||||
let payload = <E as FromWasmerMemory>::decode(memory, offset);
|
||||
RocResult::err(payload)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromWasmerMemory> FromWasmerMemory for &'_ T {
|
||||
fn decode(memory: &wasmer::Memory, offset: u32) -> Self {
|
||||
let elements = <u32 as FromWasmerMemory>::decode(memory, offset);
|
||||
|
@ -364,7 +364,7 @@ macro_rules! assert_evals_to {
|
||||
};
|
||||
|
||||
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
|
||||
$crate::helpers::wasm::assert_evals_to!($src, $expected, $ty, $transform, false);
|
||||
$crate::helpers::wasm::assert_evals_to!($src, $expected, $ty, $transform, false)
|
||||
};
|
||||
|
||||
($src:expr, $expected:expr, $ty:ty, $transform:expr, $ignore_problems: expr) => {{
|
||||
|
Loading…
Reference in New Issue
Block a user