mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
Use Layout over Variable for both build modules
This commit is contained in:
parent
db4ef45708
commit
abe9b8efaa
7 changed files with 259 additions and 206 deletions
|
@ -18,7 +18,6 @@ use roc_collections::all::ImMap;
|
||||||
use roc_module::symbol::{Interns, Symbol};
|
use roc_module::symbol::{Interns, Symbol};
|
||||||
use roc_mono::expr::{Expr, Proc, Procs};
|
use roc_mono::expr::{Expr, Proc, Procs};
|
||||||
use roc_mono::layout::{Builtin, Layout};
|
use roc_mono::layout::{Builtin, Layout};
|
||||||
use roc_types::subs::{Subs, Variable};
|
|
||||||
|
|
||||||
type Scope = ImMap<Symbol, ScopeEntry>;
|
type Scope = ImMap<Symbol, ScopeEntry>;
|
||||||
|
|
||||||
|
@ -33,7 +32,6 @@ pub enum ScopeEntry {
|
||||||
pub struct Env<'a> {
|
pub struct Env<'a> {
|
||||||
pub arena: &'a Bump,
|
pub arena: &'a Bump,
|
||||||
pub cfg: TargetFrontendConfig,
|
pub cfg: TargetFrontendConfig,
|
||||||
pub subs: Subs,
|
|
||||||
pub interns: Interns,
|
pub interns: Interns,
|
||||||
pub malloc: FuncId,
|
pub malloc: FuncId,
|
||||||
}
|
}
|
||||||
|
@ -59,7 +57,7 @@ pub fn build_expr<'a, B: Backend>(
|
||||||
pass,
|
pass,
|
||||||
fail,
|
fail,
|
||||||
cond_layout,
|
cond_layout,
|
||||||
ret_var,
|
ret_layout,
|
||||||
} => {
|
} => {
|
||||||
let branch = Branch2 {
|
let branch = Branch2 {
|
||||||
cond_lhs,
|
cond_lhs,
|
||||||
|
@ -67,7 +65,7 @@ pub fn build_expr<'a, B: Backend>(
|
||||||
pass,
|
pass,
|
||||||
fail,
|
fail,
|
||||||
cond_layout,
|
cond_layout,
|
||||||
ret_var: *ret_var,
|
ret_layout,
|
||||||
};
|
};
|
||||||
|
|
||||||
build_branch2(env, scope, module, builder, branch, procs)
|
build_branch2(env, scope, module, builder, branch, procs)
|
||||||
|
@ -76,16 +74,12 @@ pub fn build_expr<'a, B: Backend>(
|
||||||
cond,
|
cond,
|
||||||
branches,
|
branches,
|
||||||
default_branch,
|
default_branch,
|
||||||
ret_var,
|
ret_layout,
|
||||||
cond_var,
|
cond_layout,
|
||||||
} => {
|
} => {
|
||||||
let subs = &env.subs;
|
|
||||||
let ret_content = subs.get_without_compacting(*ret_var).content;
|
|
||||||
let ret_layout = Layout::from_content(env.arena, ret_content, subs)
|
|
||||||
.unwrap_or_else(|_| panic!("TODO generate a runtime error in build_expr here!"));
|
|
||||||
let ret_type = type_from_layout(env.cfg, &ret_layout);
|
let ret_type = type_from_layout(env.cfg, &ret_layout);
|
||||||
let switch_args = SwitchArgs {
|
let switch_args = SwitchArgs {
|
||||||
cond_var: *cond_var,
|
cond_layout,
|
||||||
cond_expr: cond,
|
cond_expr: cond,
|
||||||
branches,
|
branches,
|
||||||
default_branch,
|
default_branch,
|
||||||
|
@ -94,17 +88,12 @@ pub fn build_expr<'a, B: Backend>(
|
||||||
|
|
||||||
build_switch(env, scope, module, builder, switch_args, procs)
|
build_switch(env, scope, module, builder, switch_args, procs)
|
||||||
}
|
}
|
||||||
Store(ref stores, ref ret) => {
|
Store(stores, ret) => {
|
||||||
let mut scope = im_rc::HashMap::clone(scope);
|
let mut scope = im_rc::HashMap::clone(scope);
|
||||||
let arena = &env.arena;
|
|
||||||
let subs = &env.subs;
|
|
||||||
let cfg = env.cfg;
|
let cfg = env.cfg;
|
||||||
|
|
||||||
for (name, var, expr) in stores.iter() {
|
for (name, layout, expr) in stores.iter() {
|
||||||
let val = build_expr(env, &scope, module, builder, &expr, procs);
|
let val = build_expr(env, &scope, module, builder, &expr, procs);
|
||||||
let content = subs.get_without_compacting(*var).content;
|
|
||||||
let layout = Layout::from_content(arena, content, subs)
|
|
||||||
.unwrap_or_else(|()| panic!("TODO generate a runtime error for this Store!"));
|
|
||||||
let expr_type = type_from_layout(cfg, &layout);
|
let expr_type = type_from_layout(cfg, &layout);
|
||||||
|
|
||||||
let slot = builder.create_stack_slot(StackSlotData::new(
|
let slot = builder.create_stack_slot(StackSlotData::new(
|
||||||
|
@ -126,16 +115,8 @@ pub fn build_expr<'a, B: Backend>(
|
||||||
|
|
||||||
build_expr(env, &scope, module, builder, ret, procs)
|
build_expr(env, &scope, module, builder, ret, procs)
|
||||||
}
|
}
|
||||||
CallByName(ref symbol, ref args) => {
|
CallByName(symbol, args) => call_by_name(env, *symbol, args, scope, module, builder, procs),
|
||||||
let mut arg_vals = Vec::with_capacity_in(args.len(), env.arena);
|
FunctionPointer(name) => {
|
||||||
|
|
||||||
for arg in args.iter() {
|
|
||||||
arg_vals.push(build_expr(env, scope, module, builder, arg, procs));
|
|
||||||
}
|
|
||||||
|
|
||||||
call_with_args(*symbol, arg_vals.into_bump_slice(), scope, module, builder)
|
|
||||||
}
|
|
||||||
FunctionPointer(ref name) => {
|
|
||||||
let fn_id = match scope.get(name) {
|
let fn_id = match scope.get(name) {
|
||||||
Some(ScopeEntry::Func{ func_id, .. }) => *func_id,
|
Some(ScopeEntry::Func{ func_id, .. }) => *func_id,
|
||||||
other => panic!(
|
other => panic!(
|
||||||
|
@ -148,17 +129,13 @@ pub fn build_expr<'a, B: Backend>(
|
||||||
|
|
||||||
builder.ins().func_addr(env.cfg.pointer_type(), func_ref)
|
builder.ins().func_addr(env.cfg.pointer_type(), func_ref)
|
||||||
}
|
}
|
||||||
CallByPointer(ref sub_expr, ref args, ref fn_var) => {
|
CallByPointer(sub_expr, args, layout) => {
|
||||||
let subs = &env.subs;
|
|
||||||
let mut arg_vals = Vec::with_capacity_in(args.len(), env.arena);
|
let mut arg_vals = Vec::with_capacity_in(args.len(), env.arena);
|
||||||
|
|
||||||
for arg in args.iter() {
|
for arg in args.iter() {
|
||||||
arg_vals.push(build_expr(env, scope, module, builder, arg, procs));
|
arg_vals.push(build_expr(env, scope, module, builder, arg, procs));
|
||||||
}
|
}
|
||||||
|
|
||||||
let content = subs.get_without_compacting(*fn_var).content;
|
|
||||||
let layout = Layout::from_content(env.arena, content, &subs)
|
|
||||||
.unwrap_or_else(|()| panic!("TODO generate a runtime error here!"));
|
|
||||||
let sig = sig_from_layout(env.cfg, module, layout);
|
let sig = sig_from_layout(env.cfg, module, layout);
|
||||||
let callee = build_expr(env, scope, module, builder, sub_expr, procs);
|
let callee = build_expr(env, scope, module, builder, sub_expr, procs);
|
||||||
let sig_ref = builder.import_signature(sig);
|
let sig_ref = builder.import_signature(sig);
|
||||||
|
@ -296,7 +273,7 @@ struct Branch2<'a> {
|
||||||
cond_layout: &'a Layout<'a>,
|
cond_layout: &'a Layout<'a>,
|
||||||
pass: &'a Expr<'a>,
|
pass: &'a Expr<'a>,
|
||||||
fail: &'a Expr<'a>,
|
fail: &'a Expr<'a>,
|
||||||
ret_var: Variable,
|
ret_layout: &'a Layout<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_branch2<'a, B: Backend>(
|
fn build_branch2<'a, B: Backend>(
|
||||||
|
@ -307,10 +284,7 @@ fn build_branch2<'a, B: Backend>(
|
||||||
branch: Branch2<'a>,
|
branch: Branch2<'a>,
|
||||||
procs: &Procs<'a>,
|
procs: &Procs<'a>,
|
||||||
) -> Value {
|
) -> Value {
|
||||||
let subs = &env.subs;
|
let ret_layout = branch.ret_layout;
|
||||||
let ret_content = subs.get_without_compacting(branch.ret_var).content;
|
|
||||||
let ret_layout = Layout::from_content(env.arena, ret_content, subs)
|
|
||||||
.unwrap_or_else(|_| panic!("TODO generate a runtime error in build_branch2 here!"));
|
|
||||||
let ret_type = type_from_layout(env.cfg, &ret_layout);
|
let ret_type = type_from_layout(env.cfg, &ret_layout);
|
||||||
// Declare a variable which each branch will mutate to be the value of that branch.
|
// Declare a variable which each branch will mutate to be the value of that branch.
|
||||||
// At the end of the expression, we will evaluate to this.
|
// At the end of the expression, we will evaluate to this.
|
||||||
|
@ -378,7 +352,7 @@ fn build_branch2<'a, B: Backend>(
|
||||||
}
|
}
|
||||||
struct SwitchArgs<'a> {
|
struct SwitchArgs<'a> {
|
||||||
pub cond_expr: &'a Expr<'a>,
|
pub cond_expr: &'a Expr<'a>,
|
||||||
pub cond_var: Variable,
|
pub cond_layout: &'a Layout<'a>,
|
||||||
pub branches: &'a [(u64, Expr<'a>)],
|
pub branches: &'a [(u64, Expr<'a>)],
|
||||||
pub default_branch: &'a Expr<'a>,
|
pub default_branch: &'a Expr<'a>,
|
||||||
pub ret_type: Type,
|
pub ret_type: Type,
|
||||||
|
@ -471,13 +445,9 @@ pub fn declare_proc<'a, B: Backend>(
|
||||||
proc: &Proc<'a>,
|
proc: &Proc<'a>,
|
||||||
) -> (FuncId, Signature) {
|
) -> (FuncId, Signature) {
|
||||||
let args = proc.args;
|
let args = proc.args;
|
||||||
let subs = &env.subs;
|
|
||||||
let cfg = env.cfg;
|
let cfg = env.cfg;
|
||||||
// TODO this Layout::from_content is duplicated when building this Proc
|
// TODO this Layout::from_content is duplicated when building this Proc
|
||||||
let ret_content = subs.get_without_compacting(proc.ret_var).content;
|
let ret_type = type_from_layout(cfg, &proc.ret_layout);
|
||||||
let ret_layout = Layout::from_content(env.arena, ret_content, subs)
|
|
||||||
.unwrap_or_else(|_| panic!("TODO generate a runtime error in declare_proc here!"));
|
|
||||||
let ret_type = type_from_layout(cfg, &ret_layout);
|
|
||||||
|
|
||||||
// Create a signature for the function
|
// Create a signature for the function
|
||||||
let mut sig = module.make_signature();
|
let mut sig = module.make_signature();
|
||||||
|
@ -486,7 +456,7 @@ pub fn declare_proc<'a, B: Backend>(
|
||||||
sig.returns.push(AbiParam::new(ret_type));
|
sig.returns.push(AbiParam::new(ret_type));
|
||||||
|
|
||||||
// Add params to the signature
|
// Add params to the signature
|
||||||
for (layout, _name, _var) in args.iter() {
|
for (layout, _name) in args.iter() {
|
||||||
let arg_type = type_from_layout(cfg, &layout);
|
let arg_type = type_from_layout(cfg, &layout);
|
||||||
|
|
||||||
sig.params.push(AbiParam::new(arg_type));
|
sig.params.push(AbiParam::new(arg_type));
|
||||||
|
@ -513,13 +483,11 @@ pub fn define_proc_body<'a, B: Backend>(
|
||||||
procs: &Procs<'a>,
|
procs: &Procs<'a>,
|
||||||
) {
|
) {
|
||||||
let args = proc.args;
|
let args = proc.args;
|
||||||
let subs = &env.subs;
|
|
||||||
let cfg = env.cfg;
|
let cfg = env.cfg;
|
||||||
|
|
||||||
// Build the body of the function
|
// Build the body of the function
|
||||||
{
|
{
|
||||||
let mut scope = scope.clone();
|
let mut scope = scope.clone();
|
||||||
let arena = env.arena;
|
|
||||||
|
|
||||||
ctx.func.signature = sig;
|
ctx.func.signature = sig;
|
||||||
ctx.func.name = ExternalName::user(0, fn_id.as_u32());
|
ctx.func.name = ExternalName::user(0, fn_id.as_u32());
|
||||||
|
@ -533,13 +501,7 @@ pub fn define_proc_body<'a, B: Backend>(
|
||||||
builder.append_block_params_for_function_params(block);
|
builder.append_block_params_for_function_params(block);
|
||||||
|
|
||||||
// Add args to scope
|
// Add args to scope
|
||||||
for (¶m, (_, arg_symbol, var)) in builder.block_params(block).iter().zip(args) {
|
for (¶m, (layout, arg_symbol)) in builder.block_params(block).iter().zip(args) {
|
||||||
let content = subs.get_without_compacting(*var).content;
|
|
||||||
// TODO this Layout::from_content is duplicated when building this Proc
|
|
||||||
//
|
|
||||||
let layout = Layout::from_content(arena, content, subs).unwrap_or_else(|()| {
|
|
||||||
panic!("TODO generate a runtime error in define_proc_body here!")
|
|
||||||
});
|
|
||||||
let expr_type = type_from_layout(cfg, &layout);
|
let expr_type = type_from_layout(cfg, &layout);
|
||||||
|
|
||||||
scope.insert(*arg_symbol, ScopeEntry::Arg { expr_type, param });
|
scope.insert(*arg_symbol, ScopeEntry::Arg { expr_type, param });
|
||||||
|
@ -563,36 +525,60 @@ pub fn define_proc_body<'a, B: Backend>(
|
||||||
module.clear_context(ctx);
|
module.clear_context(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
fn build_arg<'a, B: Backend>(
|
||||||
fn call_with_args<'a, B: Backend>(
|
(arg, _): &'a (Expr<'a>, Layout<'a>),
|
||||||
symbol: Symbol,
|
env: &Env<'a>,
|
||||||
args: &'a [Value],
|
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
module: &mut Module<B>,
|
module: &mut Module<B>,
|
||||||
builder: &mut FunctionBuilder,
|
builder: &mut FunctionBuilder,
|
||||||
|
procs: &Procs<'a>,
|
||||||
|
) -> Value {
|
||||||
|
build_expr(env, scope, module, builder, arg, procs)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn call_by_name<'a, B: Backend>(
|
||||||
|
env: &Env<'a>,
|
||||||
|
symbol: Symbol,
|
||||||
|
args: &'a [(Expr<'a>, Layout<'a>)],
|
||||||
|
scope: &Scope,
|
||||||
|
module: &mut Module<B>,
|
||||||
|
builder: &mut FunctionBuilder,
|
||||||
|
procs: &Procs<'a>,
|
||||||
) -> Value {
|
) -> Value {
|
||||||
match symbol {
|
match symbol {
|
||||||
Symbol::NUM_ADD => {
|
Symbol::NUM_ADD => {
|
||||||
debug_assert!(args.len() == 2);
|
debug_assert!(args.len() == 2);
|
||||||
builder.ins().iadd(args[0], args[1])
|
let a = build_arg(&args[0], env, scope, module, builder, procs);
|
||||||
|
let b = build_arg(&args[1], env, scope, module, builder, procs);
|
||||||
|
|
||||||
|
builder.ins().iadd(a, b)
|
||||||
}
|
}
|
||||||
Symbol::NUM_SUB => {
|
Symbol::NUM_SUB => {
|
||||||
debug_assert!(args.len() == 2);
|
debug_assert!(args.len() == 2);
|
||||||
builder.ins().isub(args[0], args[1])
|
let a = build_arg(&args[0], env, scope, module, builder, procs);
|
||||||
|
let b = build_arg(&args[1], env, scope, module, builder, procs);
|
||||||
|
|
||||||
|
builder.ins().isub(a, b)
|
||||||
}
|
}
|
||||||
Symbol::NUM_MUL => {
|
Symbol::NUM_MUL => {
|
||||||
debug_assert!(args.len() == 2);
|
debug_assert!(args.len() == 2);
|
||||||
builder.ins().imul(args[0], args[1])
|
let a = build_arg(&args[0], env, scope, module, builder, procs);
|
||||||
|
let b = build_arg(&args[1], env, scope, module, builder, procs);
|
||||||
|
|
||||||
|
builder.ins().imul(a, b)
|
||||||
}
|
}
|
||||||
Symbol::NUM_NEG => {
|
Symbol::NUM_NEG => {
|
||||||
debug_assert!(args.len() == 1);
|
debug_assert!(args.len() == 1);
|
||||||
builder.ins().ineg(args[0])
|
let num = build_arg(&args[0], env, scope, module, builder, procs);
|
||||||
|
|
||||||
|
builder.ins().ineg(num)
|
||||||
}
|
}
|
||||||
Symbol::LIST_GET_UNSAFE => {
|
Symbol::LIST_GET_UNSAFE => {
|
||||||
debug_assert!(args.len() == 2);
|
debug_assert!(args.len() == 2);
|
||||||
|
|
||||||
let list_ptr = args[0];
|
let list_ptr = build_arg(&args[0], env, scope, module, builder, procs);
|
||||||
let elem_index = args[1];
|
let elem_index = build_arg(&args[1], env, scope, module, builder, procs);
|
||||||
|
|
||||||
let elem_type = Type::int(64).unwrap(); // TODO Look this up instead of hardcoding it!
|
let elem_type = Type::int(64).unwrap(); // TODO Look this up instead of hardcoding it!
|
||||||
let elem_bytes = 8; // TODO Look this up instead of hardcoding it!
|
let elem_bytes = 8; // TODO Look this up instead of hardcoding it!
|
||||||
|
@ -609,50 +595,73 @@ fn call_with_args<'a, B: Backend>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Symbol::LIST_SET => {
|
Symbol::LIST_SET => {
|
||||||
// set : List elem, Int, elem -> List elem
|
let (_list_expr, list_layout) = &args[0];
|
||||||
debug_assert!(args.len() == 3);
|
|
||||||
|
|
||||||
let list_ptr = args[0];
|
match list_layout {
|
||||||
let elem_index = args[1];
|
Layout::Builtin(Builtin::List(elem_layout)) => {
|
||||||
let elem = args[2];
|
// TODO try memcpy for shallow clones; it's probably faster
|
||||||
|
// let list_val = build_expr(env, scope, module, builder, list_expr, procs);
|
||||||
|
|
||||||
let elem_bytes = 8; // TODO Look this up instead of hardcoding it!
|
let num_elems = 10; // TODO FIXME read from List.len
|
||||||
let elem_size = builder.ins().iconst(types::I64, elem_bytes);
|
let elem_bytes =
|
||||||
|
elem_layout.stack_size(env.cfg.pointer_bytes() as u32) as usize;
|
||||||
|
let bytes_len = (elem_bytes * num_elems) + 1/* TODO drop the +1 when we have structs and this is no longer NUL-terminated. */;
|
||||||
|
let ptr = call_malloc(env, module, builder, bytes_len);
|
||||||
|
// let mem_flags = MemFlags::new();
|
||||||
|
|
||||||
// Multiply the requested index by the size of each element.
|
// Copy the elements from the literal into the array
|
||||||
let offset = builder.ins().imul(elem_index, elem_size);
|
// for (index, elem) in elems.iter().enumerate() {
|
||||||
|
// let offset = Offset32::new(elem_bytes as i32 * index as i32);
|
||||||
|
// let val = build_expr(env, scope, module, builder, elem, procs);
|
||||||
|
|
||||||
builder.ins().store_complex(
|
// builder.ins().store(mem_flags, val, ptr, offset);
|
||||||
MemFlags::new(),
|
// }
|
||||||
elem,
|
|
||||||
&[list_ptr, offset],
|
|
||||||
Offset32::new(0),
|
|
||||||
);
|
|
||||||
|
|
||||||
list_ptr
|
// Add a NUL terminator at the end.
|
||||||
|
// TODO: Instead of NUL-terminating, return a struct
|
||||||
|
// with the pointer and also the length and capacity.
|
||||||
|
// let nul_terminator = builder.ins().iconst(types::I8, 0);
|
||||||
|
// let index = bytes_len as i32 - 1;
|
||||||
|
// let offset = Offset32::new(index);
|
||||||
|
|
||||||
|
// builder.ins().store(mem_flags, nul_terminator, ptr, offset);
|
||||||
|
|
||||||
|
list_set_in_place(
|
||||||
|
env,
|
||||||
|
ptr,
|
||||||
|
build_arg(&args[1], env, scope, module, builder, procs),
|
||||||
|
build_arg(&args[2], env, scope, module, builder, procs),
|
||||||
|
elem_layout,
|
||||||
|
builder,
|
||||||
|
);
|
||||||
|
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!("Invalid List layout for List.set: {:?}", list_layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Symbol::LIST_SET_IN_PLACE => {
|
Symbol::LIST_SET_IN_PLACE => {
|
||||||
// set : List elem, Int, elem -> List elem
|
// set : List elem, Int, elem -> List elem
|
||||||
debug_assert!(args.len() == 3);
|
debug_assert!(args.len() == 3);
|
||||||
|
|
||||||
let list_ptr = args[0];
|
let (list_expr, list_layout) = &args[0];
|
||||||
let elem_index = args[1];
|
let list_val = build_expr(env, scope, module, builder, list_expr, procs);
|
||||||
let elem = args[2];
|
|
||||||
|
|
||||||
let elem_bytes = 8; // TODO Look this up instead of hardcoding it!
|
match list_layout {
|
||||||
let elem_size = builder.ins().iconst(types::I64, elem_bytes);
|
Layout::Builtin(Builtin::List(elem_layout)) => list_set_in_place(
|
||||||
|
env,
|
||||||
// Multiply the requested index by the size of each element.
|
list_val,
|
||||||
let offset = builder.ins().imul(elem_index, elem_size);
|
build_arg(&args[1], env, scope, module, builder, procs),
|
||||||
|
build_arg(&args[2], env, scope, module, builder, procs),
|
||||||
builder.ins().store_complex(
|
elem_layout,
|
||||||
MemFlags::new(),
|
builder,
|
||||||
elem,
|
),
|
||||||
&[list_ptr, offset],
|
_ => {
|
||||||
Offset32::new(0),
|
unreachable!("Invalid List layout for List.set: {:?}", list_layout);
|
||||||
);
|
}
|
||||||
|
}
|
||||||
list_ptr
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let fn_id = match scope.get(&symbol) {
|
let fn_id = match scope.get(&symbol) {
|
||||||
|
@ -663,7 +672,13 @@ fn call_with_args<'a, B: Backend>(
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
let local_func = module.declare_func_in_func(fn_id, &mut builder.func);
|
let local_func = module.declare_func_in_func(fn_id, &mut builder.func);
|
||||||
let call = builder.ins().call(local_func, args);
|
let mut arg_vals = Vec::with_capacity_in(args.len(), env.arena);
|
||||||
|
|
||||||
|
for (arg, _layout) in args.into_iter() {
|
||||||
|
arg_vals.push(build_expr(env, scope, module, builder, arg, procs));
|
||||||
|
}
|
||||||
|
|
||||||
|
let call = builder.ins().call(local_func, arg_vals.into_bump_slice());
|
||||||
let results = builder.inst_results(call);
|
let results = builder.inst_results(call);
|
||||||
|
|
||||||
debug_assert!(results.len() == 1);
|
debug_assert!(results.len() == 1);
|
||||||
|
@ -694,3 +709,24 @@ fn call_malloc<B: Backend>(
|
||||||
|
|
||||||
results[0]
|
results[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn list_set_in_place<'a>(
|
||||||
|
env: &Env<'a>,
|
||||||
|
list_ptr: Value,
|
||||||
|
elem_index: Value,
|
||||||
|
elem: Value,
|
||||||
|
elem_layout: &Layout<'a>,
|
||||||
|
builder: &mut FunctionBuilder,
|
||||||
|
) -> Value {
|
||||||
|
let elem_bytes = elem_layout.stack_size(env.cfg.pointer_bytes() as u32);
|
||||||
|
let elem_size = builder.ins().iconst(types::I64, elem_bytes as i64);
|
||||||
|
|
||||||
|
// Multiply the requested index by the size of each element.
|
||||||
|
let offset = builder.ins().imul(elem_index, elem_size);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.ins()
|
||||||
|
.store_complex(MemFlags::new(), elem, &[list_ptr, offset], Offset32::new(0));
|
||||||
|
|
||||||
|
list_ptr
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ pub fn type_from_layout(cfg: TargetFrontendConfig, layout: &Layout<'_>) -> Type
|
||||||
Str => cfg.pointer_type(),
|
Str => cfg.pointer_type(),
|
||||||
Map(_, _) => panic!("TODO layout_to_crane_type for Builtin::Map"),
|
Map(_, _) => panic!("TODO layout_to_crane_type for Builtin::Map"),
|
||||||
Set(_) => panic!("TODO layout_to_crane_type for Builtin::Set"),
|
Set(_) => panic!("TODO layout_to_crane_type for Builtin::Set"),
|
||||||
|
List(_) => panic!("TODO layout_to_crane_type for Builtin::List"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +38,7 @@ pub fn type_from_layout(cfg: TargetFrontendConfig, layout: &Layout<'_>) -> Type
|
||||||
pub fn sig_from_layout<B: Backend>(
|
pub fn sig_from_layout<B: Backend>(
|
||||||
cfg: TargetFrontendConfig,
|
cfg: TargetFrontendConfig,
|
||||||
module: &mut Module<B>,
|
module: &mut Module<B>,
|
||||||
layout: Layout,
|
layout: &Layout<'_>,
|
||||||
) -> Signature {
|
) -> Signature {
|
||||||
match layout {
|
match layout {
|
||||||
Layout::FunctionPointer(args, ret) => {
|
Layout::FunctionPointer(args, ret) => {
|
||||||
|
|
|
@ -13,7 +13,6 @@ use roc_collections::all::ImMap;
|
||||||
use roc_module::symbol::{Interns, Symbol};
|
use roc_module::symbol::{Interns, Symbol};
|
||||||
use roc_mono::expr::{Expr, Proc, Procs};
|
use roc_mono::expr::{Expr, Proc, Procs};
|
||||||
use roc_mono::layout::Layout;
|
use roc_mono::layout::Layout;
|
||||||
use roc_types::subs::{Subs, Variable};
|
|
||||||
|
|
||||||
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
||||||
/// output in debug builds, but we don't want it to print to stdout in release builds!
|
/// output in debug builds, but we don't want it to print to stdout in release builds!
|
||||||
|
@ -23,7 +22,7 @@ const PRINT_FN_VERIFICATION_OUTPUT: bool = true;
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
const PRINT_FN_VERIFICATION_OUTPUT: bool = false;
|
const PRINT_FN_VERIFICATION_OUTPUT: bool = false;
|
||||||
|
|
||||||
type Scope<'ctx> = ImMap<Symbol, (Variable, PointerValue<'ctx>)>;
|
type Scope<'a, 'ctx> = ImMap<Symbol, (Layout<'a>, PointerValue<'ctx>)>;
|
||||||
|
|
||||||
pub struct Env<'a, 'ctx, 'env> {
|
pub struct Env<'a, 'ctx, 'env> {
|
||||||
pub arena: &'a Bump,
|
pub arena: &'a Bump,
|
||||||
|
@ -31,13 +30,12 @@ pub struct Env<'a, 'ctx, 'env> {
|
||||||
pub builder: &'env Builder<'ctx>,
|
pub builder: &'env Builder<'ctx>,
|
||||||
pub module: &'ctx Module<'ctx>,
|
pub module: &'ctx Module<'ctx>,
|
||||||
pub interns: Interns,
|
pub interns: Interns,
|
||||||
pub subs: Subs,
|
|
||||||
pub pointer_bytes: u32,
|
pub pointer_bytes: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_expr<'a, 'ctx, 'env>(
|
pub fn build_expr<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
scope: &Scope<'ctx>,
|
scope: &Scope<'a, 'ctx>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
expr: &Expr<'a>,
|
expr: &Expr<'a>,
|
||||||
procs: &Procs<'a>,
|
procs: &Procs<'a>,
|
||||||
|
@ -52,7 +50,7 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||||
cond_rhs,
|
cond_rhs,
|
||||||
pass,
|
pass,
|
||||||
fail,
|
fail,
|
||||||
ret_var,
|
ret_layout,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let cond = Branch2 {
|
let cond = Branch2 {
|
||||||
|
@ -60,7 +58,7 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||||
cond_rhs,
|
cond_rhs,
|
||||||
pass,
|
pass,
|
||||||
fail,
|
fail,
|
||||||
ret_var: *ret_var,
|
ret_layout: ret_layout.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
build_branch2(env, scope, parent, cond, procs)
|
build_branch2(env, scope, parent, cond, procs)
|
||||||
|
@ -72,16 +70,12 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||||
cond,
|
cond,
|
||||||
branches,
|
branches,
|
||||||
default_branch,
|
default_branch,
|
||||||
ret_var,
|
ret_layout,
|
||||||
cond_var,
|
cond_layout,
|
||||||
} => {
|
} => {
|
||||||
let subs = &env.subs;
|
|
||||||
let ret_content = subs.get_without_compacting(*ret_var).content;
|
|
||||||
let ret_layout = Layout::from_content(env.arena, ret_content, subs)
|
|
||||||
.unwrap_or_else(|_| panic!("TODO generate a runtime error in build_expr here!"));
|
|
||||||
let ret_type = basic_type_from_layout(env.context, &ret_layout);
|
let ret_type = basic_type_from_layout(env.context, &ret_layout);
|
||||||
let switch_args = SwitchArgs {
|
let switch_args = SwitchArgs {
|
||||||
cond_var: *cond_var,
|
cond_layout: cond_layout.clone(),
|
||||||
cond_expr: cond,
|
cond_expr: cond,
|
||||||
branches,
|
branches,
|
||||||
default_branch,
|
default_branch,
|
||||||
|
@ -90,16 +84,11 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
build_switch(env, scope, parent, switch_args, procs)
|
build_switch(env, scope, parent, switch_args, procs)
|
||||||
}
|
}
|
||||||
Store(ref stores, ref ret) => {
|
Store(stores, ret) => {
|
||||||
let mut scope = im_rc::HashMap::clone(scope);
|
let mut scope = im_rc::HashMap::clone(scope);
|
||||||
let subs = &env.subs;
|
|
||||||
let context = &env.context;
|
let context = &env.context;
|
||||||
|
|
||||||
for (symbol, var, expr) in stores.iter() {
|
for (symbol, layout, expr) in stores.iter() {
|
||||||
let content = subs.get_without_compacting(*var).content;
|
|
||||||
let layout = Layout::from_content(env.arena, content, &subs).unwrap_or_else(|_| {
|
|
||||||
panic!("TODO generate a runtime error in build_branch2 here!")
|
|
||||||
});
|
|
||||||
let val = build_expr(env, &scope, parent, &expr, procs);
|
let val = build_expr(env, &scope, parent, &expr, procs);
|
||||||
let expr_bt = basic_type_from_layout(context, &layout);
|
let expr_bt = basic_type_from_layout(context, &layout);
|
||||||
let alloca = create_entry_block_alloca(
|
let alloca = create_entry_block_alloca(
|
||||||
|
@ -118,12 +107,12 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||||
// access itself!
|
// access itself!
|
||||||
scope = im_rc::HashMap::clone(&scope);
|
scope = im_rc::HashMap::clone(&scope);
|
||||||
|
|
||||||
scope.insert(*symbol, (*var, alloca));
|
scope.insert(*symbol, (layout.clone(), alloca));
|
||||||
}
|
}
|
||||||
|
|
||||||
build_expr(env, &scope, parent, ret, procs)
|
build_expr(env, &scope, parent, ret, procs)
|
||||||
}
|
}
|
||||||
CallByName(ref symbol, ref args) => match *symbol {
|
CallByName(symbol, args) => match *symbol {
|
||||||
Symbol::BOOL_OR => {
|
Symbol::BOOL_OR => {
|
||||||
panic!("TODO create a phi node for ||");
|
panic!("TODO create a phi node for ||");
|
||||||
}
|
}
|
||||||
|
@ -134,14 +123,14 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||||
let mut arg_vals: Vec<BasicValueEnum> =
|
let mut arg_vals: Vec<BasicValueEnum> =
|
||||||
Vec::with_capacity_in(args.len(), env.arena);
|
Vec::with_capacity_in(args.len(), env.arena);
|
||||||
|
|
||||||
for arg in args.iter() {
|
for (arg, _layout) in args.iter() {
|
||||||
arg_vals.push(build_expr(env, scope, parent, arg, procs));
|
arg_vals.push(build_expr(env, scope, parent, arg, procs));
|
||||||
}
|
}
|
||||||
|
|
||||||
call_with_args(*symbol, arg_vals.into_bump_slice(), env)
|
call_with_args(*symbol, arg_vals.into_bump_slice(), env)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
FunctionPointer(ref symbol) => {
|
FunctionPointer(symbol) => {
|
||||||
let ptr = env
|
let ptr = env
|
||||||
.module
|
.module
|
||||||
.get_function(symbol.ident_string(&env.interns))
|
.get_function(symbol.ident_string(&env.interns))
|
||||||
|
@ -151,7 +140,7 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
BasicValueEnum::PointerValue(ptr)
|
BasicValueEnum::PointerValue(ptr)
|
||||||
}
|
}
|
||||||
CallByPointer(ref sub_expr, ref args, _var) => {
|
CallByPointer(sub_expr, args, _var) => {
|
||||||
let mut arg_vals: Vec<BasicValueEnum> = Vec::with_capacity_in(args.len(), env.arena);
|
let mut arg_vals: Vec<BasicValueEnum> = Vec::with_capacity_in(args.len(), env.arena);
|
||||||
|
|
||||||
for arg in args.iter() {
|
for arg in args.iter() {
|
||||||
|
@ -266,22 +255,18 @@ struct Branch2<'a> {
|
||||||
cond_rhs: &'a Expr<'a>,
|
cond_rhs: &'a Expr<'a>,
|
||||||
pass: &'a Expr<'a>,
|
pass: &'a Expr<'a>,
|
||||||
fail: &'a Expr<'a>,
|
fail: &'a Expr<'a>,
|
||||||
ret_var: Variable,
|
ret_layout: Layout<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_branch2<'a, 'ctx, 'env>(
|
fn build_branch2<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
scope: &Scope<'ctx>,
|
scope: &Scope<'a, 'ctx>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
cond: Branch2<'a>,
|
cond: Branch2<'a>,
|
||||||
procs: &Procs<'a>,
|
procs: &Procs<'a>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
let subs = &env.subs;
|
let ret_layout = cond.ret_layout;
|
||||||
|
|
||||||
let ret_content = subs.get_without_compacting(cond.ret_var).content;
|
|
||||||
let ret_layout = Layout::from_content(env.arena, ret_content, &subs)
|
|
||||||
.unwrap_or_else(|_| panic!("TODO generate a runtime error in build_branch2 here!"));
|
|
||||||
let ret_type = basic_type_from_layout(env.context, &ret_layout);
|
let ret_type = basic_type_from_layout(env.context, &ret_layout);
|
||||||
|
|
||||||
let lhs = build_expr(env, scope, parent, cond.cond_lhs, procs);
|
let lhs = build_expr(env, scope, parent, cond.cond_lhs, procs);
|
||||||
|
@ -313,7 +298,7 @@ fn build_branch2<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
struct SwitchArgs<'a, 'ctx> {
|
struct SwitchArgs<'a, 'ctx> {
|
||||||
pub cond_expr: &'a Expr<'a>,
|
pub cond_expr: &'a Expr<'a>,
|
||||||
pub cond_var: Variable,
|
pub cond_layout: Layout<'a>,
|
||||||
pub branches: &'a [(u64, Expr<'a>)],
|
pub branches: &'a [(u64, Expr<'a>)],
|
||||||
pub default_branch: &'a Expr<'a>,
|
pub default_branch: &'a Expr<'a>,
|
||||||
pub ret_type: BasicTypeEnum<'ctx>,
|
pub ret_type: BasicTypeEnum<'ctx>,
|
||||||
|
@ -321,7 +306,7 @@ struct SwitchArgs<'a, 'ctx> {
|
||||||
|
|
||||||
fn build_switch<'a, 'ctx, 'env>(
|
fn build_switch<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
scope: &Scope<'ctx>,
|
scope: &Scope<'a, 'ctx>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
switch_args: SwitchArgs<'a, 'ctx>,
|
switch_args: SwitchArgs<'a, 'ctx>,
|
||||||
procs: &Procs<'a>,
|
procs: &Procs<'a>,
|
||||||
|
@ -392,7 +377,7 @@ fn build_switch<'a, 'ctx, 'env>(
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn build_phi2<'a, 'ctx, 'env>(
|
fn build_phi2<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
scope: &Scope<'ctx>,
|
scope: &Scope<'a, 'ctx>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
comparison: IntValue<'ctx>,
|
comparison: IntValue<'ctx>,
|
||||||
pass: &'a Expr<'a>,
|
pass: &'a Expr<'a>,
|
||||||
|
@ -474,17 +459,12 @@ pub fn build_proc_header<'a, 'ctx, 'env>(
|
||||||
) -> (FunctionValue<'ctx>, Vec<'a, BasicTypeEnum<'ctx>>) {
|
) -> (FunctionValue<'ctx>, Vec<'a, BasicTypeEnum<'ctx>>) {
|
||||||
let args = proc.args;
|
let args = proc.args;
|
||||||
let arena = env.arena;
|
let arena = env.arena;
|
||||||
let subs = &env.subs;
|
|
||||||
let context = &env.context;
|
let context = &env.context;
|
||||||
let ret_content = subs.get_without_compacting(proc.ret_var).content;
|
let ret_type = basic_type_from_layout(context, &proc.ret_layout);
|
||||||
// TODO this Layout::from_content is duplicated when building this Proc
|
|
||||||
let ret_layout = Layout::from_content(env.arena, ret_content, &subs)
|
|
||||||
.unwrap_or_else(|_| panic!("TODO generate a runtime error in build_proc here!"));
|
|
||||||
let ret_type = basic_type_from_layout(context, &ret_layout);
|
|
||||||
let mut arg_basic_types = Vec::with_capacity_in(args.len(), arena);
|
let mut arg_basic_types = Vec::with_capacity_in(args.len(), arena);
|
||||||
let mut arg_symbols = Vec::new_in(arena);
|
let mut arg_symbols = Vec::new_in(arena);
|
||||||
|
|
||||||
for (layout, arg_symbol, _var) in args.iter() {
|
for (layout, arg_symbol) in args.iter() {
|
||||||
let arg_type = basic_type_from_layout(env.context, &layout);
|
let arg_type = basic_type_from_layout(env.context, &layout);
|
||||||
|
|
||||||
arg_basic_types.push(arg_type);
|
arg_basic_types.push(arg_type);
|
||||||
|
@ -521,7 +501,7 @@ pub fn build_proc<'a, 'ctx, 'env>(
|
||||||
let mut scope = ImMap::default();
|
let mut scope = ImMap::default();
|
||||||
|
|
||||||
// Add args to scope
|
// Add args to scope
|
||||||
for ((arg_val, arg_type), (_, arg_symbol, var)) in
|
for ((arg_val, arg_type), (layout, arg_symbol)) in
|
||||||
fn_val.get_param_iter().zip(arg_basic_types).zip(args)
|
fn_val.get_param_iter().zip(arg_basic_types).zip(args)
|
||||||
{
|
{
|
||||||
set_name(arg_val, arg_symbol.ident_string(&env.interns));
|
set_name(arg_val, arg_symbol.ident_string(&env.interns));
|
||||||
|
@ -531,7 +511,7 @@ pub fn build_proc<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
builder.build_store(alloca, arg_val);
|
builder.build_store(alloca, arg_val);
|
||||||
|
|
||||||
scope.insert(*arg_symbol, (*var, alloca));
|
scope.insert(*arg_symbol, (layout.clone(), alloca));
|
||||||
}
|
}
|
||||||
|
|
||||||
let body = build_expr(env, &scope, fn_val, &proc.body, procs);
|
let body = build_expr(env, &scope, fn_val, &proc.body, procs);
|
||||||
|
@ -616,20 +596,7 @@ fn call_with_args<'a, 'ctx, 'env>(
|
||||||
Symbol::LIST_SET => {
|
Symbol::LIST_SET => {
|
||||||
debug_assert!(args.len() == 3);
|
debug_assert!(args.len() == 3);
|
||||||
|
|
||||||
let list_ptr = args[0].into_pointer_value();
|
panic!("TODO List.set with clone");
|
||||||
let elem_index = args[1].into_int_value();
|
|
||||||
let elem = args[2];
|
|
||||||
|
|
||||||
let builder = env.builder;
|
|
||||||
let elem_bytes = 8; // TODO Look this up instead of hardcoding it!
|
|
||||||
let elem_size = env.context.i64_type().const_int(elem_bytes, false);
|
|
||||||
let offset = builder.build_int_mul(elem_index, elem_size, "MUL_OFFSET");
|
|
||||||
|
|
||||||
let elem_ptr = unsafe { builder.build_gep(list_ptr, &[offset], "elem") };
|
|
||||||
|
|
||||||
builder.build_store(elem_ptr, elem);
|
|
||||||
|
|
||||||
list_ptr.into()
|
|
||||||
}
|
}
|
||||||
Symbol::LIST_SET_IN_PLACE => {
|
Symbol::LIST_SET_IN_PLACE => {
|
||||||
debug_assert!(args.len() == 3);
|
debug_assert!(args.len() == 3);
|
||||||
|
|
|
@ -56,6 +56,7 @@ pub fn basic_type_from_layout<'ctx>(
|
||||||
.as_basic_type_enum(),
|
.as_basic_type_enum(),
|
||||||
Map(_, _) => panic!("TODO layout_to_basic_type for Builtin::Map"),
|
Map(_, _) => panic!("TODO layout_to_basic_type for Builtin::Map"),
|
||||||
Set(_) => panic!("TODO layout_to_basic_type for Builtin::Set"),
|
Set(_) => panic!("TODO layout_to_basic_type for Builtin::Set"),
|
||||||
|
List(_) => panic!("TODO layout_to_basic_type for Builtin::List"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,6 @@ mod test_gen {
|
||||||
let mut procs = MutMap::default();
|
let mut procs = MutMap::default();
|
||||||
let mut env = roc_gen::crane::build::Env {
|
let mut env = roc_gen::crane::build::Env {
|
||||||
arena: &arena,
|
arena: &arena,
|
||||||
subs,
|
|
||||||
interns,
|
interns,
|
||||||
cfg,
|
cfg,
|
||||||
malloc
|
malloc
|
||||||
|
@ -73,7 +72,7 @@ mod test_gen {
|
||||||
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
|
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
|
||||||
|
|
||||||
// Populate Procs and Subs, and get the low-level Expr from the canonical Expr
|
// Populate Procs and Subs, and get the low-level Expr from the canonical Expr
|
||||||
let mono_expr = Expr::new(&arena, &env.subs, loc_expr.value, &mut procs, home, &mut ident_ids);
|
let mono_expr = Expr::new(&arena, &subs, loc_expr.value, &mut procs, home, &mut ident_ids);
|
||||||
|
|
||||||
// Put this module's ident_ids back in the interns
|
// Put this module's ident_ids back in the interns
|
||||||
env.interns.all_ident_ids.insert(home, ident_ids);
|
env.interns.all_ident_ids.insert(home, ident_ids);
|
||||||
|
@ -212,7 +211,6 @@ mod test_gen {
|
||||||
// Compile and add all the Procs before adding main
|
// Compile and add all the Procs before adding main
|
||||||
let mut env = roc_gen::llvm::build::Env {
|
let mut env = roc_gen::llvm::build::Env {
|
||||||
arena: &arena,
|
arena: &arena,
|
||||||
subs,
|
|
||||||
builder: &builder,
|
builder: &builder,
|
||||||
context: &context,
|
context: &context,
|
||||||
interns,
|
interns,
|
||||||
|
@ -223,7 +221,7 @@ mod test_gen {
|
||||||
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
|
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
|
||||||
|
|
||||||
// Populate Procs and get the low-level Expr from the canonical Expr
|
// Populate Procs and get the low-level Expr from the canonical Expr
|
||||||
let main_body = Expr::new(&arena, &env.subs, loc_expr.value, &mut procs, home, &mut ident_ids);
|
let main_body = Expr::new(&arena, &subs, loc_expr.value, &mut procs, home, &mut ident_ids);
|
||||||
|
|
||||||
// Put this module's ident_ids back in the interns, so we can use them in Env.
|
// Put this module's ident_ids back in the interns, so we can use them in Env.
|
||||||
env.interns.all_ident_ids.insert(home, ident_ids);
|
env.interns.all_ident_ids.insert(home, ident_ids);
|
||||||
|
@ -348,7 +346,6 @@ mod test_gen {
|
||||||
// Compile and add all the Procs before adding main
|
// Compile and add all the Procs before adding main
|
||||||
let mut env = roc_gen::llvm::build::Env {
|
let mut env = roc_gen::llvm::build::Env {
|
||||||
arena: &arena,
|
arena: &arena,
|
||||||
subs,
|
|
||||||
builder: &builder,
|
builder: &builder,
|
||||||
context: &context,
|
context: &context,
|
||||||
interns,
|
interns,
|
||||||
|
@ -359,7 +356,7 @@ mod test_gen {
|
||||||
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
|
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
|
||||||
|
|
||||||
// Populate Procs and get the low-level Expr from the canonical Expr
|
// Populate Procs and get the low-level Expr from the canonical Expr
|
||||||
let main_body = Expr::new(&arena, &env.subs, loc_expr.value, &mut procs, home, &mut ident_ids);
|
let main_body = Expr::new(&arena, &subs, loc_expr.value, &mut procs, home, &mut ident_ids);
|
||||||
|
|
||||||
// Put this module's ident_ids back in the interns, so we can use them in Env.
|
// Put this module's ident_ids back in the interns, so we can use them in Env.
|
||||||
env.interns.all_ident_ids.insert(home, ident_ids);
|
env.interns.all_ident_ids.insert(home, ident_ids);
|
||||||
|
@ -492,10 +489,25 @@ mod test_gen {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn set_int_list() {
|
fn set_unique_int_list() {
|
||||||
assert_evals_to!("List.getUnsafe (List.set [ 12, 9, 7, 3 ] 1 42) 1", 42, i64);
|
assert_evals_to!("List.getUnsafe (List.set [ 12, 9, 7, 3 ] 1 42) 1", 42, i64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_shared_int_list() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
shared = [ 2, 4 ]
|
||||||
|
|
||||||
|
List.getUnsafe shared 1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
4,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn branch_first_float() {
|
fn branch_first_float() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
|
|
|
@ -13,10 +13,10 @@ pub type Procs<'a> = MutMap<Symbol, Option<Proc<'a>>>;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct Proc<'a> {
|
pub struct Proc<'a> {
|
||||||
pub args: &'a [(Layout<'a>, Symbol, Variable)],
|
pub args: &'a [(Layout<'a>, Symbol)],
|
||||||
pub body: Expr<'a>,
|
pub body: Expr<'a>,
|
||||||
pub closes_over: Layout<'a>,
|
pub closes_over: Layout<'a>,
|
||||||
pub ret_var: Variable,
|
pub ret_layout: Layout<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Env<'a, 'i> {
|
struct Env<'a, 'i> {
|
||||||
|
@ -44,12 +44,12 @@ pub enum Expr<'a> {
|
||||||
|
|
||||||
// Load/Store
|
// Load/Store
|
||||||
Load(Symbol),
|
Load(Symbol),
|
||||||
Store(&'a [(Symbol, Variable, Expr<'a>)], &'a Expr<'a>),
|
Store(&'a [(Symbol, Layout<'a>, Expr<'a>)], &'a Expr<'a>),
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
FunctionPointer(Symbol),
|
FunctionPointer(Symbol),
|
||||||
CallByName(Symbol, &'a [Expr<'a>]),
|
CallByName(Symbol, &'a [(Expr<'a>, Layout<'a>)]),
|
||||||
CallByPointer(&'a Expr<'a>, &'a [Expr<'a>], Variable),
|
CallByPointer(&'a Expr<'a>, &'a [Expr<'a>], Layout<'a>),
|
||||||
|
|
||||||
// Exactly two conditional branches, e.g. if/else
|
// Exactly two conditional branches, e.g. if/else
|
||||||
Cond {
|
Cond {
|
||||||
|
@ -62,7 +62,7 @@ pub enum Expr<'a> {
|
||||||
// What to do if the condition either passes or fails
|
// What to do if the condition either passes or fails
|
||||||
pass: &'a Expr<'a>,
|
pass: &'a Expr<'a>,
|
||||||
fail: &'a Expr<'a>,
|
fail: &'a Expr<'a>,
|
||||||
ret_var: Variable,
|
ret_layout: Layout<'a>,
|
||||||
},
|
},
|
||||||
/// More than two conditional branches, e.g. a 3-way when-expression
|
/// More than two conditional branches, e.g. a 3-way when-expression
|
||||||
Branches {
|
Branches {
|
||||||
|
@ -72,24 +72,24 @@ pub enum Expr<'a> {
|
||||||
/// ( cond_rhs, pass, fail )
|
/// ( cond_rhs, pass, fail )
|
||||||
branches: &'a [(Expr<'a>, Expr<'a>, Expr<'a>)],
|
branches: &'a [(Expr<'a>, Expr<'a>, Expr<'a>)],
|
||||||
default: &'a Expr<'a>,
|
default: &'a Expr<'a>,
|
||||||
ret_var: Variable,
|
ret_layout: Layout<'a>,
|
||||||
},
|
},
|
||||||
/// Conditional branches for integers. These are more efficient.
|
/// Conditional branches for integers. These are more efficient.
|
||||||
Switch {
|
Switch {
|
||||||
/// This *must* be an integer, because Switch potentially compiles to a jump table.
|
/// This *must* be an integer, because Switch potentially compiles to a jump table.
|
||||||
cond: &'a Expr<'a>,
|
cond: &'a Expr<'a>,
|
||||||
cond_var: Variable,
|
cond_layout: Layout<'a>,
|
||||||
/// The u64 in the tuple will be compared directly to the condition Expr.
|
/// The u64 in the tuple will be compared directly to the condition Expr.
|
||||||
/// If they are equal, this branch will be taken.
|
/// If they are equal, this branch will be taken.
|
||||||
branches: &'a [(u64, Expr<'a>)],
|
branches: &'a [(u64, Expr<'a>)],
|
||||||
/// If no other branches pass, this default branch will be taken.
|
/// If no other branches pass, this default branch will be taken.
|
||||||
default_branch: &'a Expr<'a>,
|
default_branch: &'a Expr<'a>,
|
||||||
/// Each branch must return a value of this type.
|
/// Each branch must return a value of this type.
|
||||||
ret_var: Variable,
|
ret_layout: Layout<'a>,
|
||||||
},
|
},
|
||||||
Tag {
|
Tag {
|
||||||
variant_var: Variable,
|
tag_layout: Layout<'a>,
|
||||||
ext_var: Variable,
|
ext_layout: Layout<'a>,
|
||||||
name: TagName,
|
name: TagName,
|
||||||
arguments: &'a [Expr<'a>],
|
arguments: &'a [Expr<'a>],
|
||||||
},
|
},
|
||||||
|
@ -216,8 +216,6 @@ fn from_can<'a>(
|
||||||
|
|
||||||
let content = subs.get_without_compacting(*list_arg_var).content;
|
let content = subs.get_without_compacting(*list_arg_var).content;
|
||||||
|
|
||||||
dbg!("content: {:?}", &content);
|
|
||||||
|
|
||||||
match content {
|
match content {
|
||||||
Content::Structure(FlatType::Apply(
|
Content::Structure(FlatType::Apply(
|
||||||
Symbol::ATTR_ATTR,
|
Symbol::ATTR_ATTR,
|
||||||
|
@ -258,7 +256,11 @@ fn from_can<'a>(
|
||||||
args.push(from_can(env, loc_arg.value, procs, None));
|
args.push(from_can(env, loc_arg.value, procs, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::CallByPointer(&*env.arena.alloc(ptr), args.into_bump_slice(), fn_var)
|
let layout =
|
||||||
|
Layout::from_var(env.arena, fn_var, env.subs).unwrap_or_else(|err| {
|
||||||
|
panic!("TODO turn fn_var into a RuntimeError {:?}", err)
|
||||||
|
});
|
||||||
|
Expr::CallByPointer(&*env.arena.alloc(ptr), args.into_bump_slice(), layout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,8 +283,7 @@ fn from_can<'a>(
|
||||||
field_bodies.push((label, expr));
|
field_bodies.push((label, expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
let struct_content = subs.get_without_compacting(ext_var).content;
|
let struct_layout = match Layout::from_var(arena, ext_var, subs) {
|
||||||
let struct_layout = match Layout::from_content(arena, struct_content, subs) {
|
|
||||||
Ok(layout) => layout,
|
Ok(layout) => layout,
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
// Invalid field!
|
// Invalid field!
|
||||||
|
@ -305,8 +306,7 @@ fn from_can<'a>(
|
||||||
let subs = env.subs;
|
let subs = env.subs;
|
||||||
let arena = env.arena;
|
let arena = env.arena;
|
||||||
|
|
||||||
let struct_content = subs.get_without_compacting(ext_var).content;
|
let struct_layout = match Layout::from_var(arena, ext_var, subs) {
|
||||||
let struct_layout = match Layout::from_content(arena, struct_content, subs) {
|
|
||||||
Ok(layout) => layout,
|
Ok(layout) => layout,
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
// Invalid field!
|
// Invalid field!
|
||||||
|
@ -314,8 +314,7 @@ fn from_can<'a>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let field_content = subs.get_without_compacting(field_var).content;
|
let field_layout = match Layout::from_var(arena, field_var, subs) {
|
||||||
let field_layout = match Layout::from_content(arena, field_content, subs) {
|
|
||||||
Ok(layout) => layout,
|
Ok(layout) => layout,
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
// Invalid field!
|
// Invalid field!
|
||||||
|
@ -336,8 +335,7 @@ fn from_can<'a>(
|
||||||
} => {
|
} => {
|
||||||
let subs = env.subs;
|
let subs = env.subs;
|
||||||
let arena = env.arena;
|
let arena = env.arena;
|
||||||
let content = subs.get_without_compacting(elem_var).content;
|
let elem_layout = match Layout::from_var(arena, elem_var, subs) {
|
||||||
let elem_layout = match Layout::from_content(arena, content, subs) {
|
|
||||||
Ok(layout) => layout,
|
Ok(layout) => layout,
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
panic!("TODO gracefully handle List with invalid element layout");
|
panic!("TODO gracefully handle List with invalid element layout");
|
||||||
|
@ -372,9 +370,7 @@ fn add_closure<'a>(
|
||||||
let mut proc_args = Vec::with_capacity_in(loc_args.len(), arena);
|
let mut proc_args = Vec::with_capacity_in(loc_args.len(), arena);
|
||||||
|
|
||||||
for (arg_var, loc_arg) in loc_args.iter() {
|
for (arg_var, loc_arg) in loc_args.iter() {
|
||||||
let content = subs.get_without_compacting(*arg_var).content;
|
let layout = match Layout::from_var(arena, *arg_var, subs) {
|
||||||
|
|
||||||
let layout = match Layout::from_content(arena, content, subs) {
|
|
||||||
Ok(layout) => layout,
|
Ok(layout) => layout,
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
// Invalid closure!
|
// Invalid closure!
|
||||||
|
@ -391,14 +387,17 @@ fn add_closure<'a>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
proc_args.push((layout, arg_name, *arg_var));
|
proc_args.push((layout, arg_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ret_layout = Layout::from_var(arena, ret_var, subs)
|
||||||
|
.unwrap_or_else(|err| panic!("TODO handle invalid function {:?}", err));
|
||||||
|
|
||||||
let proc = Proc {
|
let proc = Proc {
|
||||||
args: proc_args.into_bump_slice(),
|
args: proc_args.into_bump_slice(),
|
||||||
body: from_can(env, can_body, procs, None),
|
body: from_can(env, can_body, procs, None),
|
||||||
closes_over: Layout::Struct(&[]),
|
closes_over: Layout::Struct(&[]),
|
||||||
ret_var,
|
ret_layout,
|
||||||
};
|
};
|
||||||
|
|
||||||
procs.insert(symbol, Some(proc));
|
procs.insert(symbol, Some(proc));
|
||||||
|
@ -412,10 +411,17 @@ fn store_pattern<'a>(
|
||||||
can_expr: roc_can::expr::Expr,
|
can_expr: roc_can::expr::Expr,
|
||||||
var: Variable,
|
var: Variable,
|
||||||
procs: &mut Procs<'a>,
|
procs: &mut Procs<'a>,
|
||||||
stored: &mut Vec<'a, (Symbol, Variable, Expr<'a>)>,
|
stored: &mut Vec<'a, (Symbol, Layout<'a>, Expr<'a>)>,
|
||||||
) {
|
) {
|
||||||
use roc_can::pattern::Pattern::*;
|
use roc_can::pattern::Pattern::*;
|
||||||
|
|
||||||
|
let layout = match Layout::from_var(env.arena, var, env.subs) {
|
||||||
|
Ok(layout) => layout,
|
||||||
|
Err(()) => {
|
||||||
|
panic!("TODO gen a runtime error here");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// If we're defining a named closure, insert it into Procs and then
|
// If we're defining a named closure, insert it into Procs and then
|
||||||
// remove the Let. When code gen later goes to look it up, it'll be in Procs!
|
// remove the Let. When code gen later goes to look it up, it'll be in Procs!
|
||||||
//
|
//
|
||||||
|
@ -430,12 +436,12 @@ fn store_pattern<'a>(
|
||||||
// identity 5
|
// identity 5
|
||||||
//
|
//
|
||||||
match can_pat {
|
match can_pat {
|
||||||
Identifier(symbol) => stored.push((symbol, var, from_can(env, can_expr, procs, None))),
|
Identifier(symbol) => stored.push((symbol, layout, from_can(env, can_expr, procs, None))),
|
||||||
Underscore => {
|
Underscore => {
|
||||||
// Since _ is never read, it's safe to reassign it.
|
// Since _ is never read, it's safe to reassign it.
|
||||||
stored.push((
|
stored.push((
|
||||||
Symbol::UNDERSCORE,
|
Symbol::UNDERSCORE,
|
||||||
var,
|
layout,
|
||||||
from_can(env, can_expr, procs, None),
|
from_can(env, can_expr, procs, None),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -503,6 +509,10 @@ fn from_can_when<'a>(
|
||||||
let cond_rhs = arena.alloc(Expr::Int(*int));
|
let cond_rhs = arena.alloc(Expr::Int(*int));
|
||||||
let pass = arena.alloc(from_can(env, loc_then.value, procs, None));
|
let pass = arena.alloc(from_can(env, loc_then.value, procs, None));
|
||||||
let fail = arena.alloc(from_can(env, loc_else.value, procs, None));
|
let fail = arena.alloc(from_can(env, loc_else.value, procs, None));
|
||||||
|
let ret_layout =
|
||||||
|
Layout::from_var(arena, expr_var, env.subs).unwrap_or_else(|err| {
|
||||||
|
panic!("TODO turn this into a RuntimeError {:?}", err)
|
||||||
|
});
|
||||||
|
|
||||||
Expr::Cond {
|
Expr::Cond {
|
||||||
cond_layout: Layout::Builtin(Builtin::Int64),
|
cond_layout: Layout::Builtin(Builtin::Int64),
|
||||||
|
@ -510,7 +520,7 @@ fn from_can_when<'a>(
|
||||||
cond_rhs,
|
cond_rhs,
|
||||||
pass,
|
pass,
|
||||||
fail,
|
fail,
|
||||||
ret_var: expr_var,
|
ret_layout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(FloatLiteral(float), FloatLiteral(_)) | (FloatLiteral(float), Underscore) => {
|
(FloatLiteral(float), FloatLiteral(_)) | (FloatLiteral(float), Underscore) => {
|
||||||
|
@ -518,6 +528,10 @@ fn from_can_when<'a>(
|
||||||
let cond_rhs = arena.alloc(Expr::Float(*float));
|
let cond_rhs = arena.alloc(Expr::Float(*float));
|
||||||
let pass = arena.alloc(from_can(env, loc_then.value, procs, None));
|
let pass = arena.alloc(from_can(env, loc_then.value, procs, None));
|
||||||
let fail = arena.alloc(from_can(env, loc_else.value, procs, None));
|
let fail = arena.alloc(from_can(env, loc_else.value, procs, None));
|
||||||
|
let ret_layout =
|
||||||
|
Layout::from_var(arena, expr_var, env.subs).unwrap_or_else(|err| {
|
||||||
|
panic!("TODO turn this into a RuntimeError {:?}", err)
|
||||||
|
});
|
||||||
|
|
||||||
Expr::Cond {
|
Expr::Cond {
|
||||||
cond_layout: Layout::Builtin(Builtin::Float64),
|
cond_layout: Layout::Builtin(Builtin::Float64),
|
||||||
|
@ -525,7 +539,7 @@ fn from_can_when<'a>(
|
||||||
cond_rhs,
|
cond_rhs,
|
||||||
pass,
|
pass,
|
||||||
fail,
|
fail,
|
||||||
ret_var: expr_var,
|
ret_layout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -538,8 +552,7 @@ fn from_can_when<'a>(
|
||||||
let arena = env.arena;
|
let arena = env.arena;
|
||||||
let cond = from_can(env, loc_cond.value, procs, None);
|
let cond = from_can(env, loc_cond.value, procs, None);
|
||||||
let subs = &env.subs;
|
let subs = &env.subs;
|
||||||
let content = subs.get_without_compacting(cond_var).content;
|
let layout = Layout::from_var(arena, cond_var, subs)
|
||||||
let layout = Layout::from_content(arena, content, subs)
|
|
||||||
.unwrap_or_else(|_| panic!("TODO generate a runtime error in from_can_when here!"));
|
.unwrap_or_else(|_| panic!("TODO generate a runtime error in from_can_when here!"));
|
||||||
|
|
||||||
// We can Switch on integers and tags, because they both have
|
// We can Switch on integers and tags, because they both have
|
||||||
|
@ -620,12 +633,21 @@ fn from_can_when<'a>(
|
||||||
debug_assert!(opt_default_branch.is_some());
|
debug_assert!(opt_default_branch.is_some());
|
||||||
let default_branch = opt_default_branch.unwrap();
|
let default_branch = opt_default_branch.unwrap();
|
||||||
|
|
||||||
|
let cond_layout =
|
||||||
|
Layout::from_var(arena, cond_var, env.subs).unwrap_or_else(|err| {
|
||||||
|
panic!("TODO turn cond_layout into a RuntimeError {:?}", err)
|
||||||
|
});
|
||||||
|
let ret_layout =
|
||||||
|
Layout::from_var(arena, expr_var, env.subs).unwrap_or_else(|err| {
|
||||||
|
panic!("TODO turn ret_layout into a RuntimeError {:?}", err)
|
||||||
|
});
|
||||||
|
|
||||||
Expr::Switch {
|
Expr::Switch {
|
||||||
cond: arena.alloc(cond),
|
cond: arena.alloc(cond),
|
||||||
branches: jumpable_branches.into_bump_slice(),
|
branches: jumpable_branches.into_bump_slice(),
|
||||||
default_branch,
|
default_branch,
|
||||||
ret_var: expr_var,
|
ret_layout,
|
||||||
cond_var,
|
cond_layout,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// /// More than two conditional branches, e.g. a 3-way when-expression
|
// /// More than two conditional branches, e.g. a 3-way when-expression
|
||||||
|
@ -652,9 +674,14 @@ fn call_by_name<'a>(
|
||||||
loc_args: std::vec::Vec<(Variable, Located<roc_can::expr::Expr>)>,
|
loc_args: std::vec::Vec<(Variable, Located<roc_can::expr::Expr>)>,
|
||||||
) -> Expr<'a> {
|
) -> Expr<'a> {
|
||||||
let mut args = Vec::with_capacity_in(loc_args.len(), env.arena);
|
let mut args = Vec::with_capacity_in(loc_args.len(), env.arena);
|
||||||
|
let subs = env.subs;
|
||||||
|
let arena = env.arena;
|
||||||
|
|
||||||
for (_, loc_arg) in loc_args {
|
for (var, loc_arg) in loc_args {
|
||||||
args.push(from_can(env, loc_arg.value, procs, None));
|
let layout = Layout::from_var(arena, var, subs)
|
||||||
|
.unwrap_or_else(|err| panic!("TODO gracefully handle bad layout: {:?}", err));
|
||||||
|
|
||||||
|
args.push((from_can(env, loc_arg.value, procs, None), layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::CallByName(proc_name, args.into_bump_slice())
|
Expr::CallByName(proc_name, args.into_bump_slice())
|
||||||
|
|
|
@ -22,17 +22,19 @@ pub enum Builtin<'a> {
|
||||||
Str,
|
Str,
|
||||||
Map(&'a Layout<'a>, &'a Layout<'a>),
|
Map(&'a Layout<'a>, &'a Layout<'a>),
|
||||||
Set(&'a Layout<'a>),
|
Set(&'a Layout<'a>),
|
||||||
|
List(&'a Layout<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Layout<'a> {
|
impl<'a> Layout<'a> {
|
||||||
|
/// Returns Err(()) if given an error, or Ok(Layout) if given a non-erroneous Structure.
|
||||||
|
/// Panics if given a FlexVar or RigidVar, since those should have been
|
||||||
|
/// monomorphized away already!
|
||||||
pub fn from_var(arena: &'a Bump, var: Variable, subs: &Subs) -> Result<Self, ()> {
|
pub fn from_var(arena: &'a Bump, var: Variable, subs: &Subs) -> Result<Self, ()> {
|
||||||
let content = subs.get_without_compacting(var).content;
|
let content = subs.get_without_compacting(var).content;
|
||||||
|
|
||||||
Self::from_content(arena, content, subs)
|
Self::from_content(arena, content, subs)
|
||||||
}
|
}
|
||||||
/// Returns Err(()) if given an error, or Ok(Layout) if given a non-erroneous Structure.
|
|
||||||
/// Panics if given a FlexVar or RigidVar, since those should have been
|
|
||||||
/// monomorphized away already!
|
|
||||||
pub fn from_content(arena: &'a Bump, content: Content, subs: &Subs) -> Result<Self, ()> {
|
pub fn from_content(arena: &'a Bump, content: Content, subs: &Subs) -> Result<Self, ()> {
|
||||||
use roc_types::subs::Content::*;
|
use roc_types::subs::Content::*;
|
||||||
|
|
||||||
|
@ -84,6 +86,7 @@ impl<'a> Builtin<'a> {
|
||||||
const STR_WORDS: u32 = 3;
|
const STR_WORDS: u32 = 3;
|
||||||
const MAP_WORDS: u32 = 6;
|
const MAP_WORDS: u32 = 6;
|
||||||
const SET_WORDS: u32 = Builtin::MAP_WORDS; // Set is an alias for Map with {} for value
|
const SET_WORDS: u32 = Builtin::MAP_WORDS; // Set is an alias for Map with {} for value
|
||||||
|
const LIST_WORDS: u32 = 3;
|
||||||
|
|
||||||
pub fn stack_size(&self, pointer_size: u32) -> u32 {
|
pub fn stack_size(&self, pointer_size: u32) -> u32 {
|
||||||
use Builtin::*;
|
use Builtin::*;
|
||||||
|
@ -94,6 +97,7 @@ impl<'a> Builtin<'a> {
|
||||||
Str => Builtin::STR_WORDS * pointer_size,
|
Str => Builtin::STR_WORDS * pointer_size,
|
||||||
Map(_, _) => Builtin::MAP_WORDS * pointer_size,
|
Map(_, _) => Builtin::MAP_WORDS * pointer_size,
|
||||||
Set(_) => Builtin::SET_WORDS * pointer_size,
|
Set(_) => Builtin::SET_WORDS * pointer_size,
|
||||||
|
List(_) => Builtin::LIST_WORDS * pointer_size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,11 +130,16 @@ fn layout_from_flat_type<'a>(
|
||||||
layout_from_num_content(content)
|
layout_from_num_content(content)
|
||||||
}
|
}
|
||||||
Symbol::STR_STR => Ok(Layout::Builtin(Builtin::Str)),
|
Symbol::STR_STR => Ok(Layout::Builtin(Builtin::Str)),
|
||||||
|
Symbol::LIST_LIST => {
|
||||||
|
let elem_layout = Layout::from_var(arena, args[0], subs)?;
|
||||||
|
|
||||||
|
Ok(Layout::Builtin(Builtin::List(arena.alloc(elem_layout))))
|
||||||
|
}
|
||||||
Symbol::ATTR_ATTR => {
|
Symbol::ATTR_ATTR => {
|
||||||
debug_assert!(args.len() == 2);
|
debug_assert!(args.len() == 2);
|
||||||
|
|
||||||
// The first argument is the uniqueness info;
|
// The first argument is the uniqueness info;
|
||||||
// we don't need that here.
|
// that doesn't affect layout, so we don't need it here.
|
||||||
let wrapped_var = args[1];
|
let wrapped_var = args[1];
|
||||||
|
|
||||||
// For now, layout is unaffected by uniqueness.
|
// For now, layout is unaffected by uniqueness.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue