mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 04:08:19 +00:00
implement List.map in the dev backend
This commit is contained in:
parent
b62ee37d8e
commit
b59ada4bc8
8 changed files with 449 additions and 21 deletions
|
@ -496,8 +496,8 @@ all = \list, predicate ->
|
|||
Break {}
|
||||
|
||||
when List.iterate list {} looper is
|
||||
Continue {} -> Bool.true
|
||||
Break {} -> Bool.false
|
||||
Continue {} -> Bool.true
|
||||
Break {} -> "" != ""
|
||||
|
||||
## Run the given function on each element of a list, and return all the
|
||||
## elements for which the function returned `Bool.true`.
|
||||
|
|
|
@ -7,13 +7,15 @@ use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
|
|||
use roc_collections::all::MutMap;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use roc_mono::code_gen_help::CodeGenHelp;
|
||||
use roc_mono::code_gen_help::{CallerProc, CodeGenHelp, HelperOp};
|
||||
use roc_mono::ir::{
|
||||
BranchInfo, JoinPointId, ListLiteralElement, Literal, Param, ProcLayout, SelfRecursive, Stmt,
|
||||
BranchInfo, HigherOrderLowLevel, JoinPointId, ListLiteralElement, Literal, Param, ProcLayout,
|
||||
SelfRecursive, Stmt,
|
||||
};
|
||||
use roc_mono::layout::{
|
||||
Builtin, InLayout, Layout, LayoutInterner, STLayoutInterner, TagIdIntType, UnionLayout,
|
||||
};
|
||||
use roc_mono::low_level::HigherOrder;
|
||||
use roc_target::TargetInfo;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
|
@ -496,6 +498,7 @@ pub struct Backend64Bit<
|
|||
interns: &'r mut Interns,
|
||||
helper_proc_gen: CodeGenHelp<'a>,
|
||||
helper_proc_symbols: Vec<'a, (Symbol, ProcLayout<'a>)>,
|
||||
caller_procs: Vec<'a, CallerProc<'a>>,
|
||||
buf: Vec<'a, u8>,
|
||||
relocs: Vec<'a, Relocation>,
|
||||
proc_name: Option<String>,
|
||||
|
@ -533,6 +536,7 @@ pub fn new_backend_64bit<
|
|||
layout_interner,
|
||||
helper_proc_gen: CodeGenHelp::new(env.arena, target_info, env.module_id),
|
||||
helper_proc_symbols: bumpalo::vec![in env.arena],
|
||||
caller_procs: bumpalo::vec![in env.arena],
|
||||
proc_name: None,
|
||||
is_self_recursive: None,
|
||||
buf: bumpalo::vec![in env.arena],
|
||||
|
@ -574,6 +578,9 @@ impl<
|
|||
fn interns(&self) -> &Interns {
|
||||
self.interns
|
||||
}
|
||||
fn interns_mut(&mut self) -> &mut Interns {
|
||||
self.interns
|
||||
}
|
||||
fn interner(&self) -> &STLayoutInterner<'a> {
|
||||
self.layout_interner
|
||||
}
|
||||
|
@ -584,12 +591,14 @@ impl<
|
|||
&mut STLayoutInterner<'a>,
|
||||
&mut Interns,
|
||||
&mut CodeGenHelp<'a>,
|
||||
&mut Vec<'a, CallerProc<'a>>,
|
||||
) {
|
||||
(
|
||||
self.env.module_id,
|
||||
self.layout_interner,
|
||||
self.interns,
|
||||
&mut self.helper_proc_gen,
|
||||
&mut self.caller_procs,
|
||||
)
|
||||
}
|
||||
fn helper_proc_gen_mut(&mut self) -> &mut CodeGenHelp<'a> {
|
||||
|
@ -1579,6 +1588,174 @@ impl<
|
|||
}
|
||||
}
|
||||
|
||||
fn build_higher_order_lowlevel(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
higher_order: &HigherOrderLowLevel<'a>,
|
||||
ret_layout: InLayout<'a>,
|
||||
) {
|
||||
let ident_ids = self
|
||||
.interns
|
||||
.all_ident_ids
|
||||
.get_mut(&self.env.module_id)
|
||||
.unwrap();
|
||||
|
||||
let (inc_n_data_symbol, inc_n_data_linker_data) = self.helper_proc_gen.gen_refcount_proc(
|
||||
ident_ids,
|
||||
self.layout_interner,
|
||||
Layout::UNIT,
|
||||
HelperOp::Inc,
|
||||
);
|
||||
|
||||
let caller_proc = CallerProc::new(
|
||||
self.env.arena,
|
||||
self.env.module_id,
|
||||
ident_ids,
|
||||
self.layout_interner,
|
||||
&higher_order.passed_function,
|
||||
higher_order.closure_env_layout,
|
||||
);
|
||||
|
||||
match higher_order.op {
|
||||
HigherOrder::ListMap { xs } => {
|
||||
let old_element_layout = higher_order.passed_function.argument_layouts[0];
|
||||
let new_element_layout = higher_order.passed_function.return_layout;
|
||||
|
||||
let input_list_layout = Layout::Builtin(Builtin::List(old_element_layout));
|
||||
let input_list_in_layout = self.layout_interner.insert(input_list_layout);
|
||||
|
||||
let caller = self.debug_symbol("caller");
|
||||
let data = self.debug_symbol("data");
|
||||
let alignment = self.debug_symbol("alignment");
|
||||
let old_element_width = self.debug_symbol("old_element_width");
|
||||
let new_element_width = self.debug_symbol("new_element_width");
|
||||
|
||||
self.load_layout_alignment(new_element_layout, alignment);
|
||||
|
||||
self.load_layout_stack_size(old_element_layout, old_element_width);
|
||||
self.load_layout_stack_size(new_element_layout, new_element_width);
|
||||
|
||||
self.helper_proc_symbols.extend(inc_n_data_linker_data);
|
||||
self.helper_proc_symbols
|
||||
.extend([(caller_proc.proc_symbol, caller_proc.proc_layout)]);
|
||||
|
||||
let inc_n_data_string = self.function_symbol_to_string(
|
||||
inc_n_data_symbol,
|
||||
std::iter::empty(),
|
||||
None,
|
||||
Layout::UNIT,
|
||||
);
|
||||
|
||||
let caller_string = self.function_symbol_to_string(
|
||||
caller_proc.proc_symbol,
|
||||
std::iter::empty(),
|
||||
None,
|
||||
Layout::UNIT,
|
||||
);
|
||||
|
||||
self.caller_procs.push(caller_proc);
|
||||
|
||||
let inc_n_data = Symbol::DEV_TMP5;
|
||||
self.build_fn_pointer(&inc_n_data, inc_n_data_string);
|
||||
|
||||
self.build_fn_pointer(&caller, caller_string);
|
||||
|
||||
if let Some(_closure_data_layout) = higher_order.closure_env_layout {
|
||||
let data_symbol = higher_order.passed_function.captured_environment;
|
||||
self.storage_manager
|
||||
.ensure_symbol_on_stack(&mut self.buf, &data_symbol);
|
||||
let (new_elem_offset, _) =
|
||||
self.storage_manager.stack_offset_and_size(&data_symbol);
|
||||
|
||||
// Load address of output element into register.
|
||||
let reg = self.storage_manager.claim_general_reg(&mut self.buf, &data);
|
||||
ASM::add_reg64_reg64_imm32(
|
||||
&mut self.buf,
|
||||
reg,
|
||||
CC::BASE_PTR_REG,
|
||||
new_elem_offset,
|
||||
);
|
||||
} else {
|
||||
// use a null pointer
|
||||
self.load_literal(&data, &Layout::U64, &Literal::Int(0u128.to_be_bytes()));
|
||||
}
|
||||
|
||||
self.load_literal(
|
||||
&Symbol::DEV_TMP3,
|
||||
&Layout::BOOL,
|
||||
&Literal::Bool(higher_order.passed_function.owns_captured_environment),
|
||||
);
|
||||
|
||||
// list: RocList,
|
||||
// caller: Caller1,
|
||||
// data: Opaque,
|
||||
// inc_n_data: IncN,
|
||||
// data_is_owned: bool,
|
||||
// alignment: u32,
|
||||
// old_element_width: usize,
|
||||
// new_element_width: usize,
|
||||
|
||||
let arguments = [
|
||||
xs,
|
||||
caller,
|
||||
data,
|
||||
inc_n_data,
|
||||
Symbol::DEV_TMP3,
|
||||
alignment,
|
||||
old_element_width,
|
||||
new_element_width,
|
||||
];
|
||||
|
||||
let ptr = Layout::U64;
|
||||
let usize_ = Layout::U64;
|
||||
|
||||
let layouts = [
|
||||
input_list_in_layout,
|
||||
ptr,
|
||||
ptr,
|
||||
ptr,
|
||||
Layout::BOOL,
|
||||
Layout::U32,
|
||||
usize_,
|
||||
usize_,
|
||||
];
|
||||
|
||||
// Setup the return location.
|
||||
let base_offset = self
|
||||
.storage_manager
|
||||
.claim_stack_area(dst, self.layout_interner.stack_size(ret_layout));
|
||||
|
||||
self.build_fn_call(
|
||||
&Symbol::DEV_TMP4,
|
||||
bitcode::LIST_MAP.to_string(),
|
||||
&arguments,
|
||||
&layouts,
|
||||
&ret_layout,
|
||||
);
|
||||
|
||||
self.free_symbol(&Symbol::DEV_TMP3);
|
||||
self.free_symbol(&Symbol::DEV_TMP5);
|
||||
|
||||
// Return list value from fn call
|
||||
self.storage_manager.copy_symbol_to_stack_offset(
|
||||
self.layout_interner,
|
||||
&mut self.buf,
|
||||
base_offset,
|
||||
&Symbol::DEV_TMP4,
|
||||
&ret_layout,
|
||||
);
|
||||
|
||||
self.free_symbol(&Symbol::DEV_TMP4);
|
||||
}
|
||||
HigherOrder::ListMap2 { xs, ys } => todo!(),
|
||||
HigherOrder::ListMap3 { xs, ys, zs } => todo!(),
|
||||
HigherOrder::ListMap4 { xs, ys, zs, ws } => {
|
||||
todo!()
|
||||
}
|
||||
HigherOrder::ListSortWith { xs } => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_list_len(&mut self, dst: &Symbol, list: &Symbol) {
|
||||
self.storage_manager.list_len(&mut self.buf, dst, list);
|
||||
}
|
||||
|
|
|
@ -12,10 +12,10 @@ use roc_error_macros::internal_error;
|
|||
use roc_module::ident::ModuleName;
|
||||
use roc_module::low_level::{LowLevel, LowLevelWrapperType};
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use roc_mono::code_gen_help::CodeGenHelp;
|
||||
use roc_mono::code_gen_help::{CallerProc, CodeGenHelp};
|
||||
use roc_mono::ir::{
|
||||
BranchInfo, CallType, Expr, JoinPointId, ListLiteralElement, Literal, Param, Proc, ProcLayout,
|
||||
SelfRecursive, Stmt,
|
||||
BranchInfo, CallType, Expr, HigherOrderLowLevel, JoinPointId, ListLiteralElement, Literal,
|
||||
Param, Proc, ProcLayout, SelfRecursive, Stmt,
|
||||
};
|
||||
use roc_mono::layout::{
|
||||
Builtin, InLayout, Layout, LayoutIds, LayoutInterner, STLayoutInterner, TagIdIntType,
|
||||
|
@ -65,8 +65,21 @@ pub enum Relocation {
|
|||
trait Backend<'a> {
|
||||
fn env(&self) -> &Env<'a>;
|
||||
fn interns(&self) -> &Interns;
|
||||
fn interns_mut(&mut self) -> &mut Interns;
|
||||
fn interner(&self) -> &STLayoutInterner<'a>;
|
||||
|
||||
fn debug_symbol(&mut self, name: &str) -> Symbol {
|
||||
let module_id = self.env().module_id;
|
||||
let ident_ids = self
|
||||
.interns_mut()
|
||||
.all_ident_ids
|
||||
.get_mut(&module_id)
|
||||
.unwrap();
|
||||
|
||||
let ident_id = ident_ids.add_str(name);
|
||||
Symbol::new(self.env().module_id, ident_id)
|
||||
}
|
||||
|
||||
// This method is suboptimal, but it seems to be the only way to make rust understand
|
||||
// that all of these values can be mutable at the same time. By returning them together,
|
||||
// rust understands that they are part of a single use of mutable self.
|
||||
|
@ -77,6 +90,7 @@ trait Backend<'a> {
|
|||
&mut STLayoutInterner<'a>,
|
||||
&mut Interns,
|
||||
&mut CodeGenHelp<'a>,
|
||||
&mut Vec<'a, CallerProc<'a>>,
|
||||
);
|
||||
|
||||
fn function_symbol_to_string<'b, I>(
|
||||
|
@ -201,7 +215,7 @@ trait Backend<'a> {
|
|||
// If this layout requires a new RC proc, we get enough info to create a linker symbol
|
||||
// for it. Here we don't create linker symbols at this time, but in Wasm backend, we do.
|
||||
let (rc_stmt, new_specializations) = {
|
||||
let (module_id, layout_interner, interns, rc_proc_gen) =
|
||||
let (module_id, layout_interner, interns, rc_proc_gen, _) =
|
||||
self.module_interns_helpers_mut();
|
||||
let ident_ids = interns.all_ident_ids.get_mut(&module_id).unwrap();
|
||||
|
||||
|
@ -319,6 +333,12 @@ trait Backend<'a> {
|
|||
ret_layout,
|
||||
..
|
||||
} => {
|
||||
dbg!(
|
||||
func_sym,
|
||||
func_sym.name() == Symbol::BOOL_TRUE,
|
||||
func_sym.name().is_builtin()
|
||||
);
|
||||
|
||||
if let LowLevelWrapperType::CanBeReplacedBy(lowlevel) =
|
||||
LowLevelWrapperType::from_symbol(func_sym.name())
|
||||
{
|
||||
|
@ -373,6 +393,9 @@ trait Backend<'a> {
|
|||
layout,
|
||||
)
|
||||
}
|
||||
CallType::HigherOrder(higher_order) => {
|
||||
self.build_higher_order_lowlevel(sym, higher_order, *layout)
|
||||
}
|
||||
x => todo!("the call type, {:?}", x),
|
||||
}
|
||||
}
|
||||
|
@ -1366,6 +1389,14 @@ trait Backend<'a> {
|
|||
/// build_list_len returns the length of a list.
|
||||
fn build_list_len(&mut self, dst: &Symbol, list: &Symbol);
|
||||
|
||||
/// generate a call to a higher-order lowlevel
|
||||
fn build_higher_order_lowlevel(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
holl: &HigherOrderLowLevel<'a>,
|
||||
ret_layout: InLayout<'a>,
|
||||
);
|
||||
|
||||
/// build_list_with_capacity creates and returns a list with the given capacity.
|
||||
fn build_list_with_capacity(
|
||||
&mut self,
|
||||
|
|
|
@ -246,10 +246,16 @@ fn build_object<'a, B: Backend<'a>>(
|
|||
|
||||
// Generate IR for specialized helper procs (refcounting & equality)
|
||||
let helper_procs = {
|
||||
let (module_id, _interner, interns, helper_proc_gen) = backend.module_interns_helpers_mut();
|
||||
let (module_id, _interner, interns, helper_proc_gen, caller_procs) =
|
||||
backend.module_interns_helpers_mut();
|
||||
|
||||
let mut owned_caller_procs = bumpalo::collections::Vec::new_in(arena);
|
||||
std::mem::swap(caller_procs, &mut owned_caller_procs);
|
||||
|
||||
let ident_ids = interns.all_ident_ids.get_mut(&module_id).unwrap();
|
||||
let helper_procs = helper_proc_gen.take_procs();
|
||||
let mut helper_procs = helper_proc_gen.take_procs();
|
||||
|
||||
helper_procs.extend(owned_caller_procs.into_iter().map(|cp| cp.proc));
|
||||
module_id.register_debug_idents(ident_ids);
|
||||
|
||||
helper_procs
|
||||
|
|
|
@ -5,8 +5,8 @@ use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
|||
use roc_target::TargetInfo;
|
||||
|
||||
use crate::ir::{
|
||||
Call, CallSpecId, CallType, Expr, HostExposedLayouts, JoinPointId, ModifyRc, Proc, ProcLayout,
|
||||
SelfRecursive, Stmt, UpdateModeId,
|
||||
Call, CallSpecId, CallType, Expr, HostExposedLayouts, JoinPointId, ModifyRc, PassedFunction,
|
||||
Proc, ProcLayout, SelfRecursive, Stmt, UpdateModeId,
|
||||
};
|
||||
use crate::layout::{
|
||||
Builtin, InLayout, LambdaName, Layout, LayoutInterner, Niche, STLayoutInterner, UnionLayout,
|
||||
|
@ -581,6 +581,175 @@ impl<'a> CodeGenHelp<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct CallerProc<'a> {
|
||||
pub proc_symbol: Symbol,
|
||||
pub proc_layout: ProcLayout<'a>,
|
||||
pub proc: Proc<'a>,
|
||||
}
|
||||
|
||||
impl<'a> CallerProc<'a> {
|
||||
fn create_symbol(home: ModuleId, ident_ids: &mut IdentIds, debug_name: &str) -> Symbol {
|
||||
let ident_id = ident_ids.add_str(debug_name);
|
||||
Symbol::new(home, ident_id)
|
||||
}
|
||||
|
||||
fn create_caller_proc_symbol(
|
||||
home: ModuleId,
|
||||
ident_ids: &mut IdentIds,
|
||||
operation: &str,
|
||||
wrapped_function: Symbol,
|
||||
) -> Symbol {
|
||||
let debug_name = format!("#help_{}_{}_{:?}", "caller", operation, wrapped_function,);
|
||||
|
||||
Self::create_symbol(home, ident_ids, &debug_name)
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
arena: &'a Bump,
|
||||
home: ModuleId,
|
||||
ident_ids: &mut IdentIds,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
passed_function: &PassedFunction<'a>,
|
||||
capture_layout: Option<InLayout<'a>>,
|
||||
) -> Self {
|
||||
let mut ctx = Context {
|
||||
new_linker_data: Vec::new_in(arena),
|
||||
recursive_union: None,
|
||||
op: HelperOp::Eq,
|
||||
};
|
||||
|
||||
let box_capture_layout = if let Some(capture_layout) = capture_layout {
|
||||
layout_interner.insert(Layout::Boxed(capture_layout))
|
||||
} else {
|
||||
layout_interner.insert(Layout::Boxed(Layout::UNIT))
|
||||
};
|
||||
|
||||
let box_argument_layout =
|
||||
layout_interner.insert(Layout::Boxed(passed_function.argument_layouts[0]));
|
||||
|
||||
let box_return_layout =
|
||||
layout_interner.insert(Layout::Boxed(passed_function.return_layout));
|
||||
|
||||
let proc_layout = ProcLayout {
|
||||
arguments: arena.alloc([box_capture_layout, box_argument_layout, box_return_layout]),
|
||||
result: Layout::UNIT,
|
||||
niche: Niche::NONE,
|
||||
};
|
||||
|
||||
let proc_symbol =
|
||||
Self::create_caller_proc_symbol(home, ident_ids, "map", passed_function.name.name());
|
||||
|
||||
ctx.new_linker_data.push((proc_symbol, proc_layout));
|
||||
|
||||
let unbox_capture = Expr::ExprUnbox {
|
||||
symbol: Symbol::ARG_1,
|
||||
};
|
||||
|
||||
let unbox_argument = Expr::ExprUnbox {
|
||||
symbol: Symbol::ARG_2,
|
||||
};
|
||||
|
||||
let unboxed_capture = Self::create_symbol(home, ident_ids, "unboxed_capture");
|
||||
let unboxed_argument = Self::create_symbol(home, ident_ids, "unboxed_argument");
|
||||
let call_result = Self::create_symbol(home, ident_ids, "call_result");
|
||||
let unit_symbol = Self::create_symbol(home, ident_ids, "unit_symbol");
|
||||
let ignored = Self::create_symbol(home, ident_ids, "ignored");
|
||||
|
||||
let call = Expr::Call(Call {
|
||||
call_type: CallType::ByName {
|
||||
name: passed_function.name,
|
||||
ret_layout: passed_function.return_layout,
|
||||
arg_layouts: passed_function.argument_layouts,
|
||||
specialization_id: passed_function.specialization_id,
|
||||
},
|
||||
arguments: if capture_layout.is_some() {
|
||||
arena.alloc([unboxed_argument, unboxed_capture])
|
||||
} else {
|
||||
arena.alloc([unboxed_argument])
|
||||
},
|
||||
});
|
||||
|
||||
let ptr_write = Expr::Call(Call {
|
||||
call_type: CallType::LowLevel {
|
||||
op: LowLevel::PtrWrite,
|
||||
update_mode: UpdateModeId::BACKEND_DUMMY,
|
||||
},
|
||||
arguments: arena.alloc([Symbol::ARG_3, call_result]),
|
||||
});
|
||||
|
||||
let mut body = Stmt::Let(
|
||||
unboxed_argument,
|
||||
unbox_argument,
|
||||
passed_function.argument_layouts[0],
|
||||
arena.alloc(Stmt::Let(
|
||||
call_result,
|
||||
call,
|
||||
passed_function.return_layout,
|
||||
arena.alloc(Stmt::Let(
|
||||
ignored,
|
||||
ptr_write,
|
||||
box_return_layout,
|
||||
arena.alloc(Stmt::Let(
|
||||
unit_symbol,
|
||||
Expr::Struct(&[]),
|
||||
Layout::UNIT,
|
||||
arena.alloc(Stmt::Ret(unit_symbol)),
|
||||
)),
|
||||
)),
|
||||
)),
|
||||
);
|
||||
|
||||
if let Some(capture_layout) = capture_layout {
|
||||
body = Stmt::Let(
|
||||
unboxed_capture,
|
||||
unbox_capture,
|
||||
capture_layout,
|
||||
arena.alloc(body),
|
||||
);
|
||||
}
|
||||
|
||||
let args: &'a [(InLayout<'a>, Symbol)] = {
|
||||
arena.alloc([
|
||||
(box_capture_layout, ARG_1),
|
||||
(box_argument_layout, ARG_2),
|
||||
(box_return_layout, ARG_3),
|
||||
])
|
||||
};
|
||||
|
||||
let proc = Proc {
|
||||
name: LambdaName::no_niche(proc_symbol),
|
||||
args,
|
||||
body,
|
||||
closure_data_layout: None,
|
||||
ret_layout: Layout::UNIT,
|
||||
is_self_recursive: SelfRecursive::NotSelfRecursive,
|
||||
host_exposed_layouts: HostExposedLayouts::NotHostExposed,
|
||||
};
|
||||
|
||||
if false {
|
||||
let allocator = ven_pretty::BoxAllocator;
|
||||
let doc = proc
|
||||
.to_doc::<_, (), _>(
|
||||
&allocator,
|
||||
layout_interner,
|
||||
true,
|
||||
crate::ir::Parens::NotNeeded,
|
||||
)
|
||||
.1
|
||||
.pretty(80)
|
||||
.to_string();
|
||||
|
||||
println!("{}", doc);
|
||||
}
|
||||
|
||||
Self {
|
||||
proc_symbol,
|
||||
proc_layout,
|
||||
proc,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn let_lowlevel<'a>(
|
||||
arena: &'a Bump,
|
||||
result_layout: InLayout<'a>,
|
||||
|
|
|
@ -1200,7 +1200,7 @@ fn list_count_if_str() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_map_on_empty_list_with_int_layout() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1218,7 +1218,7 @@ fn list_map_on_empty_list_with_int_layout() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_map_on_non_empty_list() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1236,7 +1236,7 @@ fn list_map_on_non_empty_list() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_map_changes_input() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1254,7 +1254,7 @@ fn list_map_changes_input() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_map_on_big_list() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1274,7 +1274,7 @@ fn list_map_on_big_list() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_map_with_type_change() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1293,7 +1293,7 @@ fn list_map_with_type_change() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_map_using_defined_function() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1315,7 +1315,7 @@ fn list_map_using_defined_function() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_map_all_inline() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1328,9 +1328,30 @@ fn list_map_all_inline() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_map_closure_int() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
int : I64
|
||||
int = 123
|
||||
|
||||
single : List I64
|
||||
single =
|
||||
[0]
|
||||
|
||||
List.map single (\x -> x + int)
|
||||
"#
|
||||
),
|
||||
RocList::from_slice(&[123]),
|
||||
RocList<i64>
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_map_closure() {
|
||||
fn list_map_closure_float() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
|
|
|
@ -4055,3 +4055,27 @@ fn num_abs_large_bits_min_overflow() {
|
|||
fn num_abs_float_overflow() {
|
||||
assert_evals_to!("Num.absDiff Num.maxF64 Num.minF64", f64::INFINITY, f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn bool_in_switch() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
loop : [ Continue {}, Break {} ]
|
||||
loop = Continue {}
|
||||
|
||||
all = \{} ->
|
||||
when loop is
|
||||
Continue {} -> Bool.true
|
||||
Break {} -> Bool.false
|
||||
|
||||
main = all {}
|
||||
"#
|
||||
),
|
||||
true,
|
||||
bool
|
||||
);
|
||||
}
|
||||
|
|
|
@ -210,7 +210,7 @@ pub fn helper(
|
|||
let builtins_host_tempfile =
|
||||
roc_bitcode::host_tempfile().expect("failed to write host builtins object to tempfile");
|
||||
|
||||
if false {
|
||||
if true {
|
||||
std::fs::copy(&app_o_file, "/tmp/app.o").unwrap();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue