Merge branch 'trunk' into dec-div

This commit is contained in:
Richard Feldman 2021-06-16 23:54:00 -04:00 committed by GitHub
commit 94dd8a7253
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 2448 additions and 168 deletions

View file

@ -519,7 +519,7 @@ where
}
Stmt::Join {
parameters,
continuation,
body: continuation,
remainder,
..
} => {

View file

@ -830,9 +830,10 @@ pub fn build_exp_call<'a, 'ctx, 'env>(
CallType::HigherOrderLowLevel {
op,
closure_layout,
function_owns_closure_data,
specialization_id,
arg_layouts,
ret_layout,
..
} => {
let bytes = specialization_id.to_bytes();
@ -846,8 +847,9 @@ pub fn build_exp_call<'a, 'ctx, 'env>(
scope,
layout,
*op,
*closure_layout,
func_spec,
arg_layouts,
ret_layout,
*function_owns_closure_data,
arguments,
)
@ -1436,6 +1438,12 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
structure,
wrapped: Wrapped::RecordOrSingleTagUnion,
..
}
| AccessAtIndex {
index,
structure,
wrapped: Wrapped::LikeARoseTree,
..
} => {
// extract field from a record
match load_symbol_and_layout(scope, structure) {
@ -2137,7 +2145,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
id,
parameters,
remainder,
continuation,
body: continuation,
} => {
let builder = env.builder;
let context = env.context;
@ -3161,7 +3169,7 @@ fn build_procedures_help<'a, 'ctx, 'env>(
let it = procedures.iter().map(|x| x.1);
let solutions = match roc_mono::alias_analysis::spec_program(entry_point, it) {
Err(e) => panic!("Error in alias analysis: {:?}", e),
Err(e) => panic!("Error in alias analysis: {}", e),
Ok(solutions) => solutions,
};
@ -3815,8 +3823,9 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
scope: &Scope<'a, 'ctx>,
return_layout: &Layout<'a>,
op: LowLevel,
function_layout: Layout<'a>,
func_spec: FuncSpec,
argument_layouts: &[Layout<'a>],
result_layout: &Layout<'a>,
function_owns_closure_data: bool,
args: &[Symbol],
) -> BasicValueEnum<'ctx> {
@ -3828,6 +3837,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
macro_rules! passed_function_at_index {
($index:expr) => {{
let function_symbol = args[$index];
let function_layout = Layout::FunctionPointer(argument_layouts, return_layout);
function_value_by_func_spec(env, func_spec, function_symbol, function_layout)
}};
@ -4095,7 +4105,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
env,
layout_ids,
roc_function_call,
&function_layout,
result_layout,
list,
before_layout,
after_layout,
@ -4139,7 +4149,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
env,
layout_ids,
roc_function_call,
&function_layout,
result_layout,
list,
before_layout,
after_layout,

View file

@ -601,18 +601,12 @@ pub fn list_keep_oks<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
roc_function_call: RocFunctionCall<'ctx>,
function_layout: &Layout<'a>,
// Layout of the `Result after *`
result_layout: &Layout<'a>,
list: BasicValueEnum<'ctx>,
before_layout: &Layout<'a>,
after_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
// Layout of the `Result after *`
let result_layout = match function_layout {
Layout::FunctionPointer(_, ret) => ret,
Layout::Closure(_, _, ret) => ret,
_ => unreachable!("not a callable layout"),
};
let dec_result_fn = build_dec_wrapper(env, layout_ids, result_layout);
call_bitcode_fn(
@ -638,18 +632,12 @@ pub fn list_keep_errs<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
roc_function_call: RocFunctionCall<'ctx>,
function_layout: &Layout<'a>,
// Layout of the `Result * err`
result_layout: &Layout<'a>,
list: BasicValueEnum<'ctx>,
before_layout: &Layout<'a>,
after_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
// Layout of the `Result after *`
let result_layout = match function_layout {
Layout::FunctionPointer(_, ret) => ret,
Layout::Closure(_, _, ret) => ret,
_ => unreachable!("not a callable layout"),
};
let dec_result_fn = build_dec_wrapper(env, layout_ids, result_layout);
call_bitcode_fn(

View file

@ -19,19 +19,22 @@ pub const STATIC_STR_NAME: ConstName = ConstName(&Symbol::STR_ALIAS_ANALYSIS_STA
const ENTRY_POINT_NAME: &[u8] = b"mainForHost";
pub fn func_name_bytes(proc: &Proc) -> [u8; 16] {
pub fn func_name_bytes(proc: &Proc) -> [u8; SIZE] {
func_name_bytes_help(proc.name, proc.args.iter().map(|x| x.0), proc.ret_layout)
}
const DEBUG: bool = false;
const SIZE: usize = if DEBUG { 50 } else { 16 };
pub fn func_name_bytes_help<'a, I>(
symbol: Symbol,
argument_layouts: I,
return_layout: Layout<'a>,
) -> [u8; 16]
) -> [u8; SIZE]
where
I: Iterator<Item = Layout<'a>>,
{
let mut name_bytes = [0u8; 16];
let mut name_bytes = [0u8; SIZE];
use std::collections::hash_map::DefaultHasher;
use std::hash::Hash;
@ -75,9 +78,27 @@ where
*target = *source;
}
if DEBUG {
for (i, c) in (format!("{:?}", symbol)).chars().take(25).enumerate() {
name_bytes[25 + i] = c as u8;
}
}
name_bytes
}
fn bytes_as_ascii(bytes: &[u8]) -> String {
use std::fmt::Write;
let mut buf = String::new();
for byte in bytes {
write!(buf, "{:02X}", byte).unwrap();
}
buf
}
pub fn spec_program<'a, I>(
entry_point: crate::ir::EntryPoint<'a>,
procs: I,
@ -102,15 +123,34 @@ where
m.add_const(STATIC_STR_NAME, static_str_def)?;
// the entry point wrapper
let roc_main_bytes = func_name_bytes_help(
entry_point.symbol,
entry_point.layout.arguments.iter().copied(),
entry_point.layout.result,
);
let roc_main = FuncName(&roc_main_bytes);
let entry_point_function = build_entry_point(entry_point.layout, roc_main)?;
let entry_point_name = FuncName(ENTRY_POINT_NAME);
let entry_point_function = build_entry_point(entry_point.layout, entry_point_name)?;
m.add_func(entry_point_name, entry_point_function)?;
// all other functions
for proc in procs {
let bytes = func_name_bytes(proc);
let func_name = FuncName(&bytes);
if DEBUG {
eprintln!(
"{:?}: {:?} with {:?} args",
proc.name,
bytes_as_ascii(&bytes),
proc.args.len()
);
}
let spec = proc_spec(proc)?;
m.add_func(FuncName(&func_name_bytes(proc)), spec)?;
m.add_func(func_name, spec)?;
}
m.build()?
@ -126,7 +166,9 @@ where
p.build()?
};
// eprintln!("{}", program.to_source_string());
if DEBUG {
eprintln!("{}", program.to_source_string());
}
morphic_lib::solve(program)
}
@ -198,11 +240,25 @@ fn stmt_spec(
use Stmt::*;
match stmt {
Let(symbol, expr, layout, continuation) => {
let value_id = expr_spec(builder, env, block, layout, expr)?;
Let(symbol, expr, expr_layout, mut continuation) => {
let value_id = expr_spec(builder, env, block, expr_layout, expr)?;
env.symbols.insert(*symbol, value_id);
let mut queue = vec![symbol];
while let Let(symbol, expr, expr_layout, c) = continuation {
let value_id = expr_spec(builder, env, block, expr_layout, expr)?;
env.symbols.insert(*symbol, value_id);
queue.push(symbol);
continuation = c;
}
let result = stmt_spec(builder, env, block, layout, continuation)?;
env.symbols.remove(symbol);
for symbol in queue {
env.symbols.remove(symbol);
}
Ok(result)
}
@ -235,7 +291,7 @@ fn stmt_spec(
cond_layout: _,
branches,
default_branch,
ret_layout,
ret_layout: _lies,
} => {
let mut cases = Vec::with_capacity(branches.len() + 1);
@ -246,7 +302,7 @@ fn stmt_spec(
for branch in it {
let block = builder.add_block();
let value_id = stmt_spec(builder, env, block, ret_layout, branch)?;
let value_id = stmt_spec(builder, env, block, layout, branch)?;
cases.push(BlockExpr(block, value_id));
}
@ -282,7 +338,7 @@ fn stmt_spec(
Join {
id,
parameters,
continuation,
body,
remainder,
} => {
let mut type_ids = Vec::new();
@ -298,27 +354,33 @@ fn stmt_spec(
let (jpid, jp_argument) =
builder.declare_continuation(block, jp_arg_type_id, ret_type_id)?;
// NOTE join point arguments can shadow variables from the outer scope
// the ordering of steps here is important
// add this ID so both body and remainder can reference it
env.join_points.insert(*id, jpid);
// first, with the current variable bindings, process the remainder
let cont_block = builder.add_block();
let cont_value_id = stmt_spec(builder, env, cont_block, layout, remainder)?;
// only then introduce variables bound by the jump point, and process its body
let join_body_sub_block = {
env.join_points.insert(*id, jpid);
let jp_body_block = builder.add_block();
// unpack the argument
for (i, p) in parameters.iter().enumerate() {
let value_id =
builder.add_get_tuple_field(jp_body_block, jp_argument, i as u32)?;
env.symbols.insert(p.symbol, value_id);
}
let jp_body_value_id = stmt_spec(builder, env, jp_body_block, layout, remainder)?;
let jp_body_value_id = stmt_spec(builder, env, jp_body_block, layout, body)?;
BlockExpr(jp_body_block, jp_body_value_id)
};
// NOTE the symbols bound by the join point can shadow the argument symbols of the
// surrounding function, so we don't remove them from the env here
let cont_block = builder.add_block();
let cont_value_id = stmt_spec(builder, env, cont_block, layout, continuation)?;
env.join_points.remove(id);
builder.define_continuation(jpid, join_body_sub_block)?;
@ -423,7 +485,7 @@ fn call_spec(
),
HigherOrderLowLevel {
specialization_id,
closure_layout: _,
closure_env_layout,
op,
arg_layouts,
ret_layout,
@ -458,15 +520,160 @@ fn call_spec(
DictWalk => {
let dict = env.symbols[&call.arguments[0]];
let default = env.symbols[&call.arguments[1]];
let closure_env = env.symbols[&call.arguments[3]];
let bag = builder.add_get_tuple_field(block, dict, DICT_BAG_INDEX)?;
let _cell = builder.add_get_tuple_field(block, dict, DICT_CELL_INDEX)?;
let first = builder.add_bag_get(block, bag)?;
let argument = builder.add_make_tuple(block, &[first, default])?;
let key = builder.add_get_tuple_field(block, first, 0)?;
let val = builder.add_get_tuple_field(block, first, 1)?;
let argument = if closure_env_layout.is_none() {
builder.add_make_tuple(block, &[key, val, default])?
} else {
builder.add_make_tuple(block, &[key, val, default, closure_env])?
};
builder.add_call(block, spec_var, module, name, argument)?;
}
ListWalk | ListWalkBackwards | ListWalkUntil => {
let list = env.symbols[&call.arguments[0]];
let default = env.symbols[&call.arguments[1]];
let closure_env = env.symbols[&call.arguments[3]];
let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
let _cell = builder.add_get_tuple_field(block, list, LIST_CELL_INDEX)?;
let first = builder.add_bag_get(block, bag)?;
let argument = if closure_env_layout.is_none() {
builder.add_make_tuple(block, &[first, default])?
} else {
builder.add_make_tuple(block, &[first, default, closure_env])?
};
builder.add_call(block, spec_var, module, name, argument)?;
}
ListMapWithIndex => {
let list = env.symbols[&call.arguments[0]];
let closure_env = env.symbols[&call.arguments[2]];
let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
let _cell = builder.add_get_tuple_field(block, list, LIST_CELL_INDEX)?;
let first = builder.add_bag_get(block, bag)?;
let index = builder.add_make_tuple(block, &[])?;
let argument = if closure_env_layout.is_none() {
builder.add_make_tuple(block, &[first, index])?
} else {
builder.add_make_tuple(block, &[first, index, closure_env])?
};
builder.add_call(block, spec_var, module, name, argument)?;
}
ListMap => {
let list1 = env.symbols[&call.arguments[0]];
let closure_env = env.symbols[&call.arguments[2]];
let bag1 = builder.add_get_tuple_field(block, list1, LIST_BAG_INDEX)?;
let _cell1 = builder.add_get_tuple_field(block, list1, LIST_CELL_INDEX)?;
let elem1 = builder.add_bag_get(block, bag1)?;
let argument = if closure_env_layout.is_none() {
builder.add_make_tuple(block, &[elem1])?
} else {
builder.add_make_tuple(block, &[elem1, closure_env])?
};
builder.add_call(block, spec_var, module, name, argument)?;
}
ListSortWith => {
let list1 = env.symbols[&call.arguments[0]];
let closure_env = env.symbols[&call.arguments[2]];
let bag1 = builder.add_get_tuple_field(block, list1, LIST_BAG_INDEX)?;
let _cell1 = builder.add_get_tuple_field(block, list1, LIST_CELL_INDEX)?;
let elem1 = builder.add_bag_get(block, bag1)?;
let argument = if closure_env_layout.is_none() {
builder.add_make_tuple(block, &[elem1, elem1])?
} else {
builder.add_make_tuple(block, &[elem1, elem1, closure_env])?
};
builder.add_call(block, spec_var, module, name, argument)?;
}
ListMap2 => {
let list1 = env.symbols[&call.arguments[0]];
let list2 = env.symbols[&call.arguments[1]];
let closure_env = env.symbols[&call.arguments[3]];
let bag1 = builder.add_get_tuple_field(block, list1, LIST_BAG_INDEX)?;
let _cell1 = builder.add_get_tuple_field(block, list1, LIST_CELL_INDEX)?;
let elem1 = builder.add_bag_get(block, bag1)?;
let bag2 = builder.add_get_tuple_field(block, list2, LIST_BAG_INDEX)?;
let _cell2 = builder.add_get_tuple_field(block, list2, LIST_CELL_INDEX)?;
let elem2 = builder.add_bag_get(block, bag2)?;
let argument = if closure_env_layout.is_none() {
builder.add_make_tuple(block, &[elem1, elem2])?
} else {
builder.add_make_tuple(block, &[elem1, elem2, closure_env])?
};
builder.add_call(block, spec_var, module, name, argument)?;
}
ListMap3 => {
let list1 = env.symbols[&call.arguments[0]];
let list2 = env.symbols[&call.arguments[1]];
let list3 = env.symbols[&call.arguments[2]];
let closure_env = env.symbols[&call.arguments[4]];
let bag1 = builder.add_get_tuple_field(block, list1, LIST_BAG_INDEX)?;
let _cell1 = builder.add_get_tuple_field(block, list1, LIST_CELL_INDEX)?;
let elem1 = builder.add_bag_get(block, bag1)?;
let bag2 = builder.add_get_tuple_field(block, list2, LIST_BAG_INDEX)?;
let _cell2 = builder.add_get_tuple_field(block, list2, LIST_CELL_INDEX)?;
let elem2 = builder.add_bag_get(block, bag2)?;
let bag3 = builder.add_get_tuple_field(block, list3, LIST_BAG_INDEX)?;
let _cell3 = builder.add_get_tuple_field(block, list3, LIST_CELL_INDEX)?;
let elem3 = builder.add_bag_get(block, bag3)?;
let argument = if closure_env_layout.is_none() {
builder.add_make_tuple(block, &[elem1, elem2, elem3])?
} else {
builder.add_make_tuple(block, &[elem1, elem2, elem3, closure_env])?
};
builder.add_call(block, spec_var, module, name, argument)?;
}
ListKeepIf | ListKeepOks | ListKeepErrs => {
let list = env.symbols[&call.arguments[0]];
let closure_env = env.symbols[&call.arguments[2]];
let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
// let _cell = builder.add_get_tuple_field(block, list, LIST_CELL_INDEX)?;
let first = builder.add_bag_get(block, bag)?;
let argument = if closure_env_layout.is_none() {
builder.add_make_tuple(block, &[first])?
} else {
builder.add_make_tuple(block, &[first, closure_env])?
};
let result = builder.add_call(block, spec_var, module, name, argument)?;
let unit = builder.add_tuple_type(&[])?;
builder.add_unknown_with(block, &[result], unit)?;
}
_ => {
// fake a call to the function argument
// to make sure the function is specialized
@ -653,7 +860,7 @@ fn expr_spec(
Struct(fields) => build_tuple_value(builder, env, block, fields),
AccessAtIndex {
index,
field_layouts,
field_layouts: _,
structure,
wrapped,
} => {
@ -673,17 +880,20 @@ fn expr_spec(
Wrapped::RecordOrSingleTagUnion => {
builder.add_get_tuple_field(block, value_id, *index as u32)
}
Wrapped::LikeARoseTree => {
let result_type = layout_spec(builder, layout)?;
builder.add_unknown_with(block, &[value_id], result_type)
}
Wrapped::MultiTagUnion => {
// Clearly this is not generally correct, but it should be for our examples
let hacky_is_recursive =
field_layouts.iter().any(|l| l == &Layout::RecursivePointer);
// let hacky_is_recursive = field_layouts.iter().any(|l| l == &Layout::RecursivePointer);
// if hacky_is_recursive {
if hacky_is_recursive {
let result_type = layout_spec(builder, layout)?;
builder.add_unknown_with(block, &[value_id], result_type)
} else {
builder.add_get_tuple_field(block, value_id, *index as u32)
}
// we don't know what constructor we are at this point, so how can we get a
// field from an enum value?
let result_type = layout_spec(builder, layout)?;
builder.add_unknown_with(block, &[value_id], result_type)
}
}
}
@ -700,7 +910,9 @@ fn expr_spec(
bag = builder.add_bag_insert(block, bag, value_id)?;
}
Ok(bag)
let cell = builder.add_new_heap_cell(block)?;
builder.add_make_tuple(block, &[cell, bag])
}
EmptyArray => {
@ -827,8 +1039,7 @@ fn builtin_spec(builder: &mut FuncDefBuilder, builtin: &Builtin) -> Result<TypeI
fn str_type<TC: TypeContext>(builder: &mut TC) -> Result<TypeId> {
let cell_id = builder.add_heap_cell_type();
let len_id = builder.add_tuple_type(&[])?;
builder.add_tuple_type(&[cell_id, len_id])
builder.add_tuple_type(&[cell_id])
}
// const OK_TAG_ID: u8 = 1u8;

View file

@ -193,7 +193,7 @@ impl<'a> ParamMap<'a> {
id: j,
parameters: xs,
remainder: v,
continuation: b,
body: b,
} => {
let already_in_there = self
.items
@ -393,15 +393,20 @@ impl<'a> BorrowInfState<'a> {
}
HigherOrderLowLevel {
op, closure_layout, ..
op,
arg_layouts,
ret_layout,
..
} => {
use roc_module::low_level::LowLevel::*;
debug_assert!(op.is_higher_order());
let closure_layout = Layout::FunctionPointer(arg_layouts, ret_layout);
match op {
ListMap | ListKeepIf | ListKeepOks | ListKeepErrs => {
match self.param_map.get_symbol(arguments[1], *closure_layout) {
match self.param_map.get_symbol(arguments[1], closure_layout) {
Some(function_ps) => {
// own the list if the function wants to own the element
if !function_ps[0].borrow {
@ -417,7 +422,7 @@ impl<'a> BorrowInfState<'a> {
}
}
ListMapWithIndex => {
match self.param_map.get_symbol(arguments[1], *closure_layout) {
match self.param_map.get_symbol(arguments[1], closure_layout) {
Some(function_ps) => {
// own the list if the function wants to own the element
if !function_ps[1].borrow {
@ -432,7 +437,7 @@ impl<'a> BorrowInfState<'a> {
None => unreachable!(),
}
}
ListMap2 => match self.param_map.get_symbol(arguments[2], *closure_layout) {
ListMap2 => match self.param_map.get_symbol(arguments[2], closure_layout) {
Some(function_ps) => {
// own the lists if the function wants to own the element
if !function_ps[0].borrow {
@ -450,7 +455,7 @@ impl<'a> BorrowInfState<'a> {
}
None => unreachable!(),
},
ListMap3 => match self.param_map.get_symbol(arguments[3], *closure_layout) {
ListMap3 => match self.param_map.get_symbol(arguments[3], closure_layout) {
Some(function_ps) => {
// own the lists if the function wants to own the element
if !function_ps[0].borrow {
@ -471,7 +476,7 @@ impl<'a> BorrowInfState<'a> {
None => unreachable!(),
},
ListSortWith => {
match self.param_map.get_symbol(arguments[1], *closure_layout) {
match self.param_map.get_symbol(arguments[1], closure_layout) {
Some(function_ps) => {
// always own the input list
self.own_var(arguments[0]);
@ -485,7 +490,7 @@ impl<'a> BorrowInfState<'a> {
}
}
ListWalk | ListWalkUntil | ListWalkBackwards | DictWalk => {
match self.param_map.get_symbol(arguments[2], *closure_layout) {
match self.param_map.get_symbol(arguments[2], closure_layout) {
Some(function_ps) => {
// own the data structure if the function wants to own the element
if !function_ps[0].borrow {
@ -618,7 +623,7 @@ impl<'a> BorrowInfState<'a> {
id: j,
parameters: ys,
remainder: v,
continuation: b,
body: b,
} => {
let old = self.param_set.clone();
self.update_param_set(ys);

View file

@ -597,7 +597,7 @@ fn to_relevant_branch_help<'a>(
start.extend(end);
}
}
Wrapped::RecordOrSingleTagUnion => {
Wrapped::RecordOrSingleTagUnion | Wrapped::LikeARoseTree => {
let sub_positions = arguments.into_iter().enumerate().map(
|(index, (pattern, _))| {
let mut new_path = path.to_vec();
@ -956,7 +956,7 @@ pub fn optimize_when<'a>(
stmt = Stmt::Join {
id,
parameters: &[],
continuation: env.arena.alloc(body),
body: env.arena.alloc(body),
remainder: env.arena.alloc(stmt),
};
}
@ -1329,7 +1329,7 @@ fn compile_guard<'a>(
id,
parameters: arena.alloc([param]),
remainder: stmt,
continuation: arena.alloc(cond),
body: arena.alloc(cond),
}
}
@ -1622,7 +1622,7 @@ fn decide_to_branching<'a>(
Stmt::Join {
id: fail_jp_id,
parameters: &[],
continuation: fail,
body: fail,
remainder: arena.alloc(test_stmt),
}
}

View file

@ -622,7 +622,7 @@ fn expand_and_cancel<'a>(env: &mut Env<'a, '_>, stmt: &'a Stmt<'a>) -> &'a Stmt<
Join {
id,
parameters,
continuation,
body: continuation,
remainder,
} => {
let continuation = expand_and_cancel(env, continuation);
@ -631,7 +631,7 @@ fn expand_and_cancel<'a>(env: &mut Env<'a, '_>, stmt: &'a Stmt<'a>) -> &'a Stmt<
let stmt = Join {
id: *id,
parameters,
continuation,
body: continuation,
remainder,
};

View file

@ -64,7 +64,7 @@ pub fn occurring_variables(stmt: &Stmt<'_>) -> (MutSet<Symbol>, MutSet<Symbol>)
Join {
parameters,
continuation,
body: continuation,
remainder,
..
} => {
@ -455,7 +455,7 @@ impl<'a> Context<'a> {
HigherOrderLowLevel {
op,
closure_layout,
closure_env_layout,
specialization_id,
arg_layouts,
ret_layout,
@ -467,7 +467,7 @@ impl<'a> Context<'a> {
call_type: if let Some(OWNED) = $borrows.map(|p| p.borrow) {
HigherOrderLowLevel {
op: *op,
closure_layout: *closure_layout,
closure_env_layout: *closure_env_layout,
function_owns_closure_data: true,
specialization_id: *specialization_id,
arg_layouts,
@ -497,12 +497,14 @@ impl<'a> Context<'a> {
const FUNCTION: bool = BORROWED;
const CLOSURE_DATA: bool = BORROWED;
let function_layout = Layout::FunctionPointer(arg_layouts, ret_layout);
match op {
roc_module::low_level::LowLevel::ListMap
| roc_module::low_level::LowLevel::ListKeepIf
| roc_module::low_level::LowLevel::ListKeepOks
| roc_module::low_level::LowLevel::ListKeepErrs => {
match self.param_map.get_symbol(arguments[1], *closure_layout) {
match self.param_map.get_symbol(arguments[1], function_layout) {
Some(function_ps) => {
let borrows = [function_ps[0].borrow, FUNCTION, CLOSURE_DATA];
@ -524,7 +526,7 @@ impl<'a> Context<'a> {
}
}
roc_module::low_level::LowLevel::ListMapWithIndex => {
match self.param_map.get_symbol(arguments[1], *closure_layout) {
match self.param_map.get_symbol(arguments[1], function_layout) {
Some(function_ps) => {
let borrows = [function_ps[1].borrow, FUNCTION, CLOSURE_DATA];
@ -545,7 +547,7 @@ impl<'a> Context<'a> {
}
}
roc_module::low_level::LowLevel::ListMap2 => {
match self.param_map.get_symbol(arguments[2], *closure_layout) {
match self.param_map.get_symbol(arguments[2], function_layout) {
Some(function_ps) => {
let borrows = [
function_ps[0].borrow,
@ -572,7 +574,7 @@ impl<'a> Context<'a> {
}
}
roc_module::low_level::LowLevel::ListMap3 => {
match self.param_map.get_symbol(arguments[3], *closure_layout) {
match self.param_map.get_symbol(arguments[3], function_layout) {
Some(function_ps) => {
let borrows = [
function_ps[0].borrow,
@ -601,7 +603,7 @@ impl<'a> Context<'a> {
}
}
roc_module::low_level::LowLevel::ListSortWith => {
match self.param_map.get_symbol(arguments[1], *closure_layout) {
match self.param_map.get_symbol(arguments[1], function_layout) {
Some(function_ps) => {
let borrows = [OWNED, FUNCTION, CLOSURE_DATA];
@ -623,7 +625,7 @@ impl<'a> Context<'a> {
| roc_module::low_level::LowLevel::ListWalkUntil
| roc_module::low_level::LowLevel::ListWalkBackwards
| roc_module::low_level::LowLevel::DictWalk => {
match self.param_map.get_symbol(arguments[2], *closure_layout) {
match self.param_map.get_symbol(arguments[2], function_layout) {
Some(function_ps) => {
// borrow data structure based on first argument of the folded function
// borrow the default based on second argument of the folded function
@ -978,7 +980,7 @@ impl<'a> Context<'a> {
id: j,
parameters: _,
remainder: b,
continuation: v,
body: v,
} => {
// get the parameters with borrow signature
let xs = self.param_map.get_join_point(*j);
@ -1000,7 +1002,7 @@ impl<'a> Context<'a> {
id: *j,
parameters: xs,
remainder: b,
continuation: v,
body: v,
}),
b_live_vars,
)
@ -1143,7 +1145,7 @@ pub fn collect_stmt(
id: j,
parameters,
remainder: b,
continuation: v,
body: v,
} => {
let mut j_live_vars = collect_stmt(v, jp_live_vars, MutSet::default());
for param in parameters.iter() {

View file

@ -890,9 +890,10 @@ pub enum Stmt<'a> {
Join {
id: JoinPointId,
parameters: &'a [Param<'a>],
/// does not contain jumps to this id
continuation: &'a Stmt<'a>,
/// the "body" of the join point, contains the jumps to this id
/// body of the join point
/// what happens after _jumping to_ the join point
body: &'a Stmt<'a>,
/// what happens after _defining_ the join point
remainder: &'a Stmt<'a>,
},
Jump(JoinPointId, &'a [Symbol]),
@ -1013,6 +1014,8 @@ pub enum Wrapped {
EmptyRecord,
SingleElementRecord,
RecordOrSingleTagUnion,
/// Like a rose tree; recursive, but only one tag
LikeARoseTree,
MultiTagUnion,
}
@ -1045,7 +1048,7 @@ impl Wrapped {
},
_ => Some(Wrapped::MultiTagUnion),
},
NonNullableUnwrapped(_) => Some(Wrapped::RecordOrSingleTagUnion),
NonNullableUnwrapped(_) => Some(Wrapped::LikeARoseTree),
NullableWrapped { .. } | NullableUnwrapped { .. } => {
Some(Wrapped::MultiTagUnion)
@ -1151,7 +1154,7 @@ pub enum CallType<'a> {
HigherOrderLowLevel {
op: LowLevel,
/// the layout of the closure argument, if any
closure_layout: Layout<'a>,
closure_env_layout: Option<Layout<'a>>,
/// specialization id of the function argument
specialization_id: CallSpecId,
/// does the function need to own the closure data
@ -1476,7 +1479,7 @@ impl<'a> Stmt<'a> {
Join {
id,
parameters,
continuation,
body: continuation,
remainder,
} => {
let it = parameters.iter().map(|p| symbol_to_doc(alloc, p.symbol));
@ -2712,8 +2715,6 @@ macro_rules! match_on_closure_argument {
let arena = $env.arena;
let function_layout = arena.alloc(top_level).full();
let arg_layouts = top_level.arguments;
let ret_layout = top_level.result;
@ -2723,10 +2724,10 @@ macro_rules! match_on_closure_argument {
$env,
lambda_set,
$closure_data_symbol,
|top_level_function, closure_data, function_layout, specialization_id| self::Call {
|top_level_function, closure_data, closure_env_layout, specialization_id| self::Call {
call_type: CallType::HigherOrderLowLevel {
op: $op,
closure_layout: function_layout,
closure_env_layout,
specialization_id,
function_owns_closure_data: false,
arg_layouts,
@ -2734,7 +2735,6 @@ macro_rules! match_on_closure_argument {
},
arguments: arena.alloc([$($x,)* top_level_function, closure_data]),
},
function_layout,
$layout,
$assigned,
$hole,
@ -3328,7 +3328,7 @@ pub fn with_hole<'a>(
id,
parameters: env.arena.alloc([param]),
remainder: env.arena.alloc(stmt),
continuation: hole,
body: hole,
}
}
}
@ -3381,7 +3381,7 @@ pub fn with_hole<'a>(
id,
parameters: env.arena.alloc([param]),
remainder: env.arena.alloc(stmt),
continuation: env.arena.alloc(hole),
body: env.arena.alloc(hole),
}
}
@ -4275,7 +4275,10 @@ fn convert_tag_union<'a>(
)
}
Unwrapped(_, field_layouts) => {
Unwrapped {
arguments: field_layouts,
..
} => {
let field_symbols_temp = sorted_field_symbols(env, procs, layout_cache, args);
let mut field_symbols = Vec::with_capacity_in(field_layouts.len(), env.arena);
@ -5327,7 +5330,7 @@ fn substitute_in_stmt_help<'a>(
id,
parameters,
remainder,
continuation,
body: continuation,
} => {
let opt_remainder = substitute_in_stmt_help(arena, remainder, subs);
let opt_continuation = substitute_in_stmt_help(arena, continuation, subs);
@ -5340,7 +5343,7 @@ fn substitute_in_stmt_help<'a>(
id: *id,
parameters,
remainder,
continuation,
body: continuation,
}))
} else {
None
@ -7013,7 +7016,10 @@ fn from_can_pattern_help<'a>(
union,
}
}
Unwrapped(_, field_layouts) => {
Unwrapped {
arguments: field_layouts,
..
} => {
let union = crate::exhaustive::Union {
render_as: RenderAs::Tag,
alternatives: vec![Ctor {
@ -7708,13 +7714,12 @@ fn lowlevel_match_on_lambda_set<'a, ToLowLevelCall>(
lambda_set: LambdaSet<'a>,
closure_data_symbol: Symbol,
to_lowlevel_call: ToLowLevelCall,
function_layout: Layout<'a>,
return_layout: Layout<'a>,
assigned: Symbol,
hole: &'a Stmt<'a>,
) -> Stmt<'a>
where
ToLowLevelCall: Fn(Symbol, Symbol, Layout<'a>, CallSpecId) -> Call<'a> + Copy,
ToLowLevelCall: Fn(Symbol, Symbol, Option<Layout<'a>>, CallSpecId) -> Call<'a> + Copy,
{
match lambda_set.runtime_representation() {
Layout::Union(_) => {
@ -7726,8 +7731,8 @@ where
closure_tag_id_symbol,
Layout::Builtin(crate::layout::TAG_SIZE),
closure_data_symbol,
lambda_set.is_represented(),
to_lowlevel_call,
function_layout,
return_layout,
assigned,
hole,
@ -7755,7 +7760,7 @@ where
let call = to_lowlevel_call(
function_symbol,
closure_data_symbol,
function_layout,
lambda_set.is_represented(),
call_spec_id,
);
@ -7770,8 +7775,8 @@ where
closure_tag_id_symbol,
Layout::Builtin(Builtin::Int1),
closure_data_symbol,
lambda_set.is_represented(),
to_lowlevel_call,
function_layout,
return_layout,
assigned,
hole,
@ -7786,8 +7791,8 @@ where
closure_tag_id_symbol,
Layout::Builtin(Builtin::Int8),
closure_data_symbol,
lambda_set.is_represented(),
to_lowlevel_call,
function_layout,
return_layout,
assigned,
hole,
@ -7804,14 +7809,14 @@ fn lowlevel_union_lambda_set_to_switch<'a, ToLowLevelCall>(
closure_tag_id_symbol: Symbol,
closure_tag_id_layout: Layout<'a>,
closure_data_symbol: Symbol,
closure_env_layout: Option<Layout<'a>>,
to_lowlevel_call: ToLowLevelCall,
function_layout: Layout<'a>,
return_layout: Layout<'a>,
assigned: Symbol,
hole: &'a Stmt<'a>,
) -> Stmt<'a>
where
ToLowLevelCall: Fn(Symbol, Symbol, Layout<'a>, CallSpecId) -> Call<'a> + Copy,
ToLowLevelCall: Fn(Symbol, Symbol, Option<Layout<'a>>, CallSpecId) -> Call<'a> + Copy,
{
debug_assert!(!lambda_set.is_empty());
@ -7828,7 +7833,7 @@ where
let call = to_lowlevel_call(
*function_symbol,
closure_data_symbol,
function_layout,
closure_env_layout,
call_spec_id,
);
let stmt = build_call(env, call, assigned, return_layout, env.arena.alloc(hole));
@ -7859,7 +7864,7 @@ where
Stmt::Join {
id: join_point_id,
parameters: &*env.arena.alloc([param]),
continuation: hole,
body: hole,
remainder: env.arena.alloc(switch),
}
}
@ -8017,7 +8022,7 @@ fn union_lambda_set_to_switch<'a>(
Stmt::Join {
id: join_point_id,
parameters: &*env.arena.alloc([param]),
continuation: hole,
body: hole,
remainder: env.arena.alloc(switch),
}
}
@ -8161,7 +8166,7 @@ fn enum_lambda_set_to_switch<'a>(
Stmt::Join {
id: join_point_id,
parameters: &*env.arena.alloc([param]),
continuation: hole,
body: hole,
remainder: env.arena.alloc(switch),
}
}
@ -8229,14 +8234,14 @@ fn lowlevel_enum_lambda_set_to_switch<'a, ToLowLevelCall>(
closure_tag_id_symbol: Symbol,
closure_tag_id_layout: Layout<'a>,
closure_data_symbol: Symbol,
closure_env_layout: Option<Layout<'a>>,
to_lowlevel_call: ToLowLevelCall,
function_layout: Layout<'a>,
return_layout: Layout<'a>,
assigned: Symbol,
hole: &'a Stmt<'a>,
) -> Stmt<'a>
where
ToLowLevelCall: Fn(Symbol, Symbol, Layout<'a>, CallSpecId) -> Call<'a> + Copy,
ToLowLevelCall: Fn(Symbol, Symbol, Option<Layout<'a>>, CallSpecId) -> Call<'a> + Copy,
{
debug_assert!(!lambda_set.is_empty());
@ -8253,7 +8258,7 @@ where
let call = to_lowlevel_call(
*function_symbol,
closure_data_symbol,
function_layout,
closure_env_layout,
call_spec_id,
);
let stmt = build_call(
@ -8290,7 +8295,7 @@ where
Stmt::Join {
id: join_point_id,
parameters: &*env.arena.alloc([param]),
continuation: hole,
body: hole,
remainder: env.arena.alloc(switch),
}
}

View file

@ -143,6 +143,14 @@ impl<'a> LambdaSet<'a> {
*self.representation
}
pub fn is_represented(&self) -> Option<Layout<'a>> {
if let Layout::Struct(&[]) = self.representation {
None
} else {
Some(*self.representation)
}
}
pub fn layout_for_member(&self, function_symbol: Symbol) -> ClosureRepresentation<'a> {
debug_assert!(
self.set.iter().any(|(s, _)| *s == function_symbol),
@ -281,7 +289,9 @@ impl<'a> LambdaSet<'a> {
Unit | UnitWithArguments => Layout::Struct(&[]),
BoolUnion { .. } => Layout::Builtin(Builtin::Int1),
ByteUnion(_) => Layout::Builtin(Builtin::Int8),
Unwrapped(_tag_name, layouts) => Layout::Struct(layouts.into_bump_slice()),
Unwrapped {
arguments: layouts, ..
} => Layout::Struct(layouts.into_bump_slice()),
Wrapped(variant) => {
use WrappedVariant::*;
@ -1266,9 +1276,15 @@ pub enum UnionVariant<'a> {
Never,
Unit,
UnitWithArguments,
BoolUnion { ttrue: TagName, ffalse: TagName },
BoolUnion {
ttrue: TagName,
ffalse: TagName,
},
ByteUnion(Vec<'a, TagName>),
Unwrapped(TagName, Vec<'a, Layout<'a>>),
Unwrapped {
tag_name: TagName,
arguments: Vec<'a, Layout<'a>>,
},
Wrapped(WrappedVariant<'a>),
}
@ -1486,7 +1502,10 @@ pub fn union_sorted_tags_help<'a>(
fields: layouts.into_bump_slice(),
})
} else {
UnionVariant::Unwrapped(tag_name, layouts)
UnionVariant::Unwrapped {
tag_name,
arguments: layouts,
}
}
}
num_tags => {
@ -1638,7 +1657,10 @@ pub fn layout_from_tag_union<'a>(
Unit | UnitWithArguments => Layout::Struct(&[]),
BoolUnion { .. } => Layout::Builtin(Builtin::Int1),
ByteUnion(_) => Layout::Builtin(Builtin::Int8),
Unwrapped(_, mut field_layouts) => {
Unwrapped {
arguments: mut field_layouts,
..
} => {
if field_layouts.len() == 1 {
field_layouts.pop().unwrap()
} else {

View file

@ -60,7 +60,7 @@ pub fn make_tail_recursive<'a>(
id,
remainder: jump,
parameters: params,
continuation: new,
body: new,
}
}
}
@ -160,7 +160,7 @@ fn insert_jumps<'a>(
id,
parameters,
remainder,
continuation,
body: continuation,
} => {
let opt_remainder = insert_jumps(arena, remainder, goal_id, needle);
let opt_continuation = insert_jumps(arena, continuation, goal_id, needle);
@ -173,7 +173,7 @@ fn insert_jumps<'a>(
id: *id,
parameters,
remainder,
continuation,
body: continuation,
}))
} else {
None