mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 03:42:17 +00:00
Put the capture niche in the lambda name instead of generating new names
This commit is contained in:
parent
1ed2e1a8e9
commit
019ebd93f7
20 changed files with 592 additions and 486 deletions
|
@ -23,11 +23,13 @@ pub const STATIC_LIST_NAME: ConstName = ConstName(b"THIS IS A STATIC LIST");
|
||||||
const ENTRY_POINT_NAME: &[u8] = b"mainForHost";
|
const ENTRY_POINT_NAME: &[u8] = b"mainForHost";
|
||||||
|
|
||||||
pub fn func_name_bytes(proc: &Proc) -> [u8; SIZE] {
|
pub fn func_name_bytes(proc: &Proc) -> [u8; SIZE] {
|
||||||
func_name_bytes_help(
|
let bytes = func_name_bytes_help(
|
||||||
proc.name.call_name(),
|
proc.name.name(),
|
||||||
proc.args.iter().map(|x| x.0),
|
proc.args.iter().map(|x| x.0),
|
||||||
|
proc.name.captures_niche.iter().copied(),
|
||||||
&proc.ret_layout,
|
&proc.ret_layout,
|
||||||
)
|
);
|
||||||
|
bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -65,13 +67,15 @@ impl TagUnionId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn func_name_bytes_help<'a, I>(
|
pub fn func_name_bytes_help<'a, I1, I2>(
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
argument_layouts: I,
|
argument_layouts: I2,
|
||||||
|
captures_niche: I1,
|
||||||
return_layout: &Layout<'a>,
|
return_layout: &Layout<'a>,
|
||||||
) -> [u8; SIZE]
|
) -> [u8; SIZE]
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = Layout<'a>>,
|
I1: IntoIterator<Item = Layout<'a>>,
|
||||||
|
I2: IntoIterator<Item = Layout<'a>>,
|
||||||
{
|
{
|
||||||
let mut name_bytes = [0u8; SIZE];
|
let mut name_bytes = [0u8; SIZE];
|
||||||
|
|
||||||
|
@ -86,6 +90,10 @@ where
|
||||||
layout.hash(&mut hasher);
|
layout.hash(&mut hasher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for capture_layout in captures_niche {
|
||||||
|
capture_layout.hash(&mut hasher);
|
||||||
|
}
|
||||||
|
|
||||||
return_layout.hash(&mut hasher);
|
return_layout.hash(&mut hasher);
|
||||||
|
|
||||||
hasher.finish()
|
hasher.finish()
|
||||||
|
@ -177,13 +185,17 @@ where
|
||||||
match layout {
|
match layout {
|
||||||
RawFunctionLayout::Function(_, _, _) => {
|
RawFunctionLayout::Function(_, _, _) => {
|
||||||
let it = top_level.arguments.iter().copied();
|
let it = top_level.arguments.iter().copied();
|
||||||
let bytes = func_name_bytes_help(*symbol, it, &top_level.result);
|
let bytes = func_name_bytes_help(*symbol, it, [], &top_level.result);
|
||||||
|
|
||||||
host_exposed_functions.push((bytes, top_level.arguments));
|
host_exposed_functions.push((bytes, top_level.arguments));
|
||||||
}
|
}
|
||||||
RawFunctionLayout::ZeroArgumentThunk(_) => {
|
RawFunctionLayout::ZeroArgumentThunk(_) => {
|
||||||
let bytes =
|
let bytes = func_name_bytes_help(
|
||||||
func_name_bytes_help(*symbol, [Layout::UNIT], &top_level.result);
|
*symbol,
|
||||||
|
[Layout::UNIT],
|
||||||
|
[],
|
||||||
|
&top_level.result,
|
||||||
|
);
|
||||||
|
|
||||||
host_exposed_functions.push((bytes, top_level.arguments));
|
host_exposed_functions.push((bytes, top_level.arguments));
|
||||||
}
|
}
|
||||||
|
@ -211,6 +223,7 @@ where
|
||||||
let roc_main_bytes = func_name_bytes_help(
|
let roc_main_bytes = func_name_bytes_help(
|
||||||
entry_point.symbol,
|
entry_point.symbol,
|
||||||
entry_point.layout.arguments.iter().copied(),
|
entry_point.layout.arguments.iter().copied(),
|
||||||
|
std::iter::empty(),
|
||||||
&entry_point.layout.result,
|
&entry_point.layout.result,
|
||||||
);
|
);
|
||||||
let roc_main = FuncName(&roc_main_bytes);
|
let roc_main = FuncName(&roc_main_bytes);
|
||||||
|
@ -635,7 +648,7 @@ fn call_spec(
|
||||||
|
|
||||||
match &call.call_type {
|
match &call.call_type {
|
||||||
ByName {
|
ByName {
|
||||||
name: symbol,
|
name,
|
||||||
ret_layout,
|
ret_layout,
|
||||||
arg_layouts,
|
arg_layouts,
|
||||||
specialization_id,
|
specialization_id,
|
||||||
|
@ -644,8 +657,9 @@ fn call_spec(
|
||||||
let spec_var = CalleeSpecVar(&array);
|
let spec_var = CalleeSpecVar(&array);
|
||||||
|
|
||||||
let arg_value_id = build_tuple_value(builder, env, block, call.arguments)?;
|
let arg_value_id = build_tuple_value(builder, env, block, call.arguments)?;
|
||||||
let it = arg_layouts.iter().copied();
|
let args_it = arg_layouts.iter().copied();
|
||||||
let bytes = func_name_bytes_help(*symbol, it, ret_layout);
|
let captures_it = name.captures_niche.iter().copied();
|
||||||
|
let bytes = func_name_bytes_help(name.name(), args_it, captures_it, ret_layout);
|
||||||
let name = FuncName(&bytes);
|
let name = FuncName(&bytes);
|
||||||
let module = MOD_APP;
|
let module = MOD_APP;
|
||||||
builder.add_call(block, spec_var, module, name, arg_value_id)
|
builder.add_call(block, spec_var, module, name, arg_value_id)
|
||||||
|
@ -688,9 +702,14 @@ fn call_spec(
|
||||||
let mode = update_mode.to_bytes();
|
let mode = update_mode.to_bytes();
|
||||||
let update_mode_var = UpdateModeVar(&mode);
|
let update_mode_var = UpdateModeVar(&mode);
|
||||||
|
|
||||||
let it = passed_function.argument_layouts.iter().copied();
|
let args_it = passed_function.argument_layouts.iter().copied();
|
||||||
let bytes =
|
let captures_it = passed_function.name.captures_niche.iter().copied();
|
||||||
func_name_bytes_help(passed_function.name, it, &passed_function.return_layout);
|
let bytes = func_name_bytes_help(
|
||||||
|
passed_function.name.name(),
|
||||||
|
args_it,
|
||||||
|
captures_it,
|
||||||
|
&passed_function.return_layout,
|
||||||
|
);
|
||||||
let name = FuncName(&bytes);
|
let name = FuncName(&bytes);
|
||||||
let module = MOD_APP;
|
let module = MOD_APP;
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ pub enum DecWidth {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
|
||||||
pub enum FloatWidth {
|
pub enum FloatWidth {
|
||||||
F32,
|
F32,
|
||||||
F64,
|
F64,
|
||||||
|
@ -76,7 +76,7 @@ impl FloatWidth {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
|
||||||
pub enum IntWidth {
|
pub enum IntWidth {
|
||||||
U8 = 0,
|
U8 = 0,
|
||||||
U16 = 1,
|
U16 = 1,
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::annotation::make_apply_symbol;
|
||||||
use crate::annotation::IntroducedVariables;
|
use crate::annotation::IntroducedVariables;
|
||||||
use crate::annotation::OwnedNamedOrAble;
|
use crate::annotation::OwnedNamedOrAble;
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
|
use crate::expr::AccessorData;
|
||||||
use crate::expr::AnnotatedMark;
|
use crate::expr::AnnotatedMark;
|
||||||
use crate::expr::ClosureData;
|
use crate::expr::ClosureData;
|
||||||
use crate::expr::Declarations;
|
use crate::expr::Declarations;
|
||||||
|
@ -1554,7 +1555,10 @@ fn canonicalize_pending_value_def<'a>(
|
||||||
region: loc_ann.region,
|
region: loc_ann.region,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let symbol = scope.gen_unique_symbol();
|
let symbol = match &loc_can_pattern.value {
|
||||||
|
Pattern::Identifier(symbol) => *symbol,
|
||||||
|
_ => scope.gen_unique_symbol(),
|
||||||
|
};
|
||||||
|
|
||||||
// generate a fake pattern for each argument. this makes signatures
|
// generate a fake pattern for each argument. this makes signatures
|
||||||
// that are functions only crash when they are applied.
|
// that are functions only crash when they are applied.
|
||||||
|
@ -1725,6 +1729,36 @@ fn canonicalize_pending_body<'a>(
|
||||||
(loc_can_expr, def_references)
|
(loc_can_expr, def_references)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Turn f = .foo into f = \rcd -[f]-> rcd.foo
|
||||||
|
// (
|
||||||
|
// Pattern::Identifier(defined_symbol)
|
||||||
|
// | Pattern::AbilityMemberSpecialization {
|
||||||
|
// ident: defined_symbol,
|
||||||
|
// ..
|
||||||
|
// },
|
||||||
|
// ast::Expr::AccessorFunction(field),
|
||||||
|
// ) => {
|
||||||
|
// let (loc_can_expr, can_output) = (
|
||||||
|
// Loc::at(
|
||||||
|
// loc_expr.region,
|
||||||
|
// Accessor(AccessorData {
|
||||||
|
// name: scope.gen_unique_symbol(),
|
||||||
|
// function_var: var_store.fresh(),
|
||||||
|
// record_var: var_store.fresh(),
|
||||||
|
// ext_var: var_store.fresh(),
|
||||||
|
// closure_var: var_store.fresh(),
|
||||||
|
// field_var: var_store.fresh(),
|
||||||
|
// field: (*field).into(),
|
||||||
|
// }),
|
||||||
|
// ),
|
||||||
|
// Output::default(),
|
||||||
|
// );
|
||||||
|
// let def_references = DefReferences::Value(can_output.references.clone());
|
||||||
|
// output.union(can_output);
|
||||||
|
|
||||||
|
// (loc_can_expr, def_references)
|
||||||
|
// }
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
let (loc_can_expr, can_output) =
|
let (loc_can_expr, can_output) =
|
||||||
canonicalize_expr(env, var_store, scope, loc_expr.region, &loc_expr.value);
|
canonicalize_expr(env, var_store, scope, loc_expr.region, &loc_expr.value);
|
||||||
|
|
|
@ -106,8 +106,8 @@ trait Backend<'a> {
|
||||||
proc: Proc<'a>,
|
proc: Proc<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
) -> (Vec<u8>, Vec<Relocation>, Vec<'a, (Symbol, String)>) {
|
) -> (Vec<u8>, Vec<Relocation>, Vec<'a, (Symbol, String)>) {
|
||||||
let layout_id = layout_ids.get(proc.name.call_name(), &proc.ret_layout);
|
let layout_id = layout_ids.get(proc.name.name(), &proc.ret_layout);
|
||||||
let proc_name = self.symbol_to_string(proc.name.call_name(), layout_id);
|
let proc_name = self.symbol_to_string(proc.name.name(), layout_id);
|
||||||
self.reset(proc_name, proc.is_self_recursive);
|
self.reset(proc_name, proc.is_self_recursive);
|
||||||
self.load_args(proc.args, &proc.ret_layout);
|
self.load_args(proc.args, &proc.ret_layout);
|
||||||
for (layout, sym) in proc.args {
|
for (layout, sym) in proc.args {
|
||||||
|
@ -263,7 +263,7 @@ trait Backend<'a> {
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
if let LowLevelWrapperType::CanBeReplacedBy(lowlevel) =
|
if let LowLevelWrapperType::CanBeReplacedBy(lowlevel) =
|
||||||
LowLevelWrapperType::from_symbol(*func_sym)
|
LowLevelWrapperType::from_symbol(func_sym.name())
|
||||||
{
|
{
|
||||||
self.build_run_low_level(
|
self.build_run_low_level(
|
||||||
sym,
|
sym,
|
||||||
|
@ -272,14 +272,20 @@ trait Backend<'a> {
|
||||||
arg_layouts,
|
arg_layouts,
|
||||||
ret_layout,
|
ret_layout,
|
||||||
)
|
)
|
||||||
} else if self.defined_in_app_module(*func_sym) {
|
} else if self.defined_in_app_module(func_sym.name()) {
|
||||||
let layout_id = LayoutIds::default().get(*func_sym, layout);
|
let layout_id = LayoutIds::default().get(func_sym.name(), layout);
|
||||||
let fn_name = self.symbol_to_string(*func_sym, layout_id);
|
let fn_name = self.symbol_to_string(func_sym.name(), layout_id);
|
||||||
// Now that the arguments are needed, load them if they are literals.
|
// Now that the arguments are needed, load them if they are literals.
|
||||||
self.load_literal_symbols(arguments);
|
self.load_literal_symbols(arguments);
|
||||||
self.build_fn_call(sym, fn_name, arguments, arg_layouts, ret_layout)
|
self.build_fn_call(sym, fn_name, arguments, arg_layouts, ret_layout)
|
||||||
} else {
|
} else {
|
||||||
self.build_builtin(sym, *func_sym, arguments, arg_layouts, ret_layout)
|
self.build_builtin(
|
||||||
|
sym,
|
||||||
|
func_sym.name(),
|
||||||
|
arguments,
|
||||||
|
arg_layouts,
|
||||||
|
ret_layout,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,9 @@ use roc_mono::ir::{
|
||||||
BranchInfo, CallType, EntryPoint, HigherOrderLowLevel, JoinPointId, ListLiteralElement,
|
BranchInfo, CallType, EntryPoint, HigherOrderLowLevel, JoinPointId, ListLiteralElement,
|
||||||
ModifyRc, OptLevel, ProcLayout,
|
ModifyRc, OptLevel, ProcLayout,
|
||||||
};
|
};
|
||||||
use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, TagIdIntType, UnionLayout};
|
use roc_mono::layout::{
|
||||||
|
Builtin, LambdaName, LambdaSet, Layout, LayoutIds, TagIdIntType, UnionLayout,
|
||||||
|
};
|
||||||
use roc_std::RocDec;
|
use roc_std::RocDec;
|
||||||
use roc_target::{PtrWidth, TargetInfo};
|
use roc_target::{PtrWidth, TargetInfo};
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
|
@ -715,7 +717,7 @@ fn promote_to_main_function<'a, 'ctx, 'env>(
|
||||||
top_level: ProcLayout<'a>,
|
top_level: ProcLayout<'a>,
|
||||||
) -> (&'static str, FunctionValue<'ctx>) {
|
) -> (&'static str, FunctionValue<'ctx>) {
|
||||||
let it = top_level.arguments.iter().copied();
|
let it = top_level.arguments.iter().copied();
|
||||||
let bytes = roc_alias_analysis::func_name_bytes_help(symbol, it, &top_level.result);
|
let bytes = roc_alias_analysis::func_name_bytes_help(symbol, it, [], &top_level.result);
|
||||||
let func_name = FuncName(&bytes);
|
let func_name = FuncName(&bytes);
|
||||||
let func_solutions = mod_solutions.func_solutions(func_name).unwrap();
|
let func_solutions = mod_solutions.func_solutions(func_name).unwrap();
|
||||||
|
|
||||||
|
@ -727,7 +729,7 @@ fn promote_to_main_function<'a, 'ctx, 'env>(
|
||||||
);
|
);
|
||||||
|
|
||||||
// NOTE fake layout; it is only used for debug prints
|
// NOTE fake layout; it is only used for debug prints
|
||||||
let roc_main_fn = function_value_by_func_spec(env, *func_spec, symbol, &[], &Layout::UNIT);
|
let roc_main_fn = function_value_by_func_spec(env, *func_spec, symbol, &[], &[], &Layout::UNIT);
|
||||||
|
|
||||||
let main_fn_name = "$Test.main";
|
let main_fn_name = "$Test.main";
|
||||||
|
|
||||||
|
@ -3296,6 +3298,7 @@ fn expose_function_to_host<'a, 'ctx, 'env>(
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
roc_function: FunctionValue<'ctx>,
|
roc_function: FunctionValue<'ctx>,
|
||||||
arguments: &'a [Layout<'a>],
|
arguments: &'a [Layout<'a>],
|
||||||
|
captures_niche: &'a [Layout<'a>],
|
||||||
return_layout: Layout<'a>,
|
return_layout: Layout<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
) {
|
) {
|
||||||
|
@ -3304,6 +3307,7 @@ fn expose_function_to_host<'a, 'ctx, 'env>(
|
||||||
let proc_layout = ProcLayout {
|
let proc_layout = ProcLayout {
|
||||||
arguments,
|
arguments,
|
||||||
result: return_layout,
|
result: return_layout,
|
||||||
|
captures_niche,
|
||||||
};
|
};
|
||||||
|
|
||||||
let c_function_name: String = layout_ids
|
let c_function_name: String = layout_ids
|
||||||
|
@ -4185,7 +4189,7 @@ fn build_procedures_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
// only have top-level thunks for this proc's module in scope
|
// only have top-level thunks for this proc's module in scope
|
||||||
// this retain is not needed for correctness, but will cause less confusion when debugging
|
// this retain is not needed for correctness, but will cause less confusion when debugging
|
||||||
let home = proc.name.call_name().module_id();
|
let home = proc.name.name().module_id();
|
||||||
current_scope.retain_top_level_thunks_for_module(home);
|
current_scope.retain_top_level_thunks_for_module(home);
|
||||||
|
|
||||||
build_proc(
|
build_proc(
|
||||||
|
@ -4301,6 +4305,7 @@ fn build_proc_header<'a, 'ctx, 'env>(
|
||||||
symbol,
|
symbol,
|
||||||
fn_val,
|
fn_val,
|
||||||
arguments.into_bump_slice(),
|
arguments.into_bump_slice(),
|
||||||
|
proc.name.captures_niche,
|
||||||
proc.ret_layout,
|
proc.ret_layout,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
);
|
);
|
||||||
|
@ -4530,8 +4535,12 @@ pub fn build_proc<'a, 'ctx, 'env>(
|
||||||
// * roc__mainForHost_1_Update_result_size() -> i64
|
// * roc__mainForHost_1_Update_result_size() -> i64
|
||||||
|
|
||||||
let it = top_level.arguments.iter().copied();
|
let it = top_level.arguments.iter().copied();
|
||||||
let bytes =
|
let bytes = roc_alias_analysis::func_name_bytes_help(
|
||||||
roc_alias_analysis::func_name_bytes_help(symbol, it, &top_level.result);
|
symbol,
|
||||||
|
it,
|
||||||
|
[],
|
||||||
|
&top_level.result,
|
||||||
|
);
|
||||||
let func_name = FuncName(&bytes);
|
let func_name = FuncName(&bytes);
|
||||||
let func_solutions = mod_solutions.func_solutions(func_name).unwrap();
|
let func_solutions = mod_solutions.func_solutions(func_name).unwrap();
|
||||||
|
|
||||||
|
@ -4548,6 +4557,7 @@ pub fn build_proc<'a, 'ctx, 'env>(
|
||||||
*func_spec,
|
*func_spec,
|
||||||
symbol,
|
symbol,
|
||||||
top_level.arguments,
|
top_level.arguments,
|
||||||
|
&[],
|
||||||
&top_level.result,
|
&top_level.result,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -4559,7 +4569,7 @@ pub fn build_proc<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let ident_string = proc.name.call_name().as_str(&env.interns);
|
let ident_string = proc.name.name().as_str(&env.interns);
|
||||||
let fn_name: String = format!("{}_1", ident_string);
|
let fn_name: String = format!("{}_1", ident_string);
|
||||||
|
|
||||||
build_closure_caller(
|
build_closure_caller(
|
||||||
|
@ -4624,17 +4634,19 @@ fn function_value_by_func_spec<'a, 'ctx, 'env>(
|
||||||
func_spec: FuncSpec,
|
func_spec: FuncSpec,
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
arguments: &[Layout<'a>],
|
arguments: &[Layout<'a>],
|
||||||
|
captures_niche: &[Layout<'a>],
|
||||||
result: &Layout<'a>,
|
result: &Layout<'a>,
|
||||||
) -> FunctionValue<'ctx> {
|
) -> FunctionValue<'ctx> {
|
||||||
let fn_name = func_spec_name(env.arena, &env.interns, symbol, func_spec);
|
let fn_name = func_spec_name(env.arena, &env.interns, symbol, func_spec);
|
||||||
let fn_name = fn_name.as_str();
|
let fn_name = fn_name.as_str();
|
||||||
|
|
||||||
function_value_by_name_help(env, arguments, result, symbol, fn_name)
|
function_value_by_name_help(env, arguments, captures_niche, result, symbol, fn_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_value_by_name_help<'a, 'ctx, 'env>(
|
fn function_value_by_name_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
arguments: &[Layout<'a>],
|
arguments: &[Layout<'a>],
|
||||||
|
_captures_niche: &[Layout<'a>],
|
||||||
result: &Layout<'a>,
|
result: &Layout<'a>,
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
|
@ -4675,12 +4687,18 @@ fn roc_call_with_args<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
argument_layouts: &[Layout<'a>],
|
argument_layouts: &[Layout<'a>],
|
||||||
result_layout: &Layout<'a>,
|
result_layout: &Layout<'a>,
|
||||||
symbol: Symbol,
|
name: LambdaName<'a>,
|
||||||
func_spec: FuncSpec,
|
func_spec: FuncSpec,
|
||||||
arguments: &[BasicValueEnum<'ctx>],
|
arguments: &[BasicValueEnum<'ctx>],
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let fn_val =
|
let fn_val = function_value_by_func_spec(
|
||||||
function_value_by_func_spec(env, func_spec, symbol, argument_layouts, result_layout);
|
env,
|
||||||
|
func_spec,
|
||||||
|
name.name(),
|
||||||
|
argument_layouts,
|
||||||
|
name.captures_niche,
|
||||||
|
result_layout,
|
||||||
|
);
|
||||||
|
|
||||||
call_roc_function(env, fn_val, result_layout, arguments)
|
call_roc_function(env, fn_val, result_layout, arguments)
|
||||||
}
|
}
|
||||||
|
@ -4869,8 +4887,9 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
let function = function_value_by_func_spec(
|
let function = function_value_by_func_spec(
|
||||||
env,
|
env,
|
||||||
func_spec,
|
func_spec,
|
||||||
function_name,
|
function_name.name(),
|
||||||
argument_layouts,
|
argument_layouts,
|
||||||
|
function_name.captures_niche,
|
||||||
return_layout,
|
return_layout,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -380,7 +380,7 @@ impl<'a> WasmBackend<'a> {
|
||||||
println!("\ngenerating procedure {:?}\n", proc.name);
|
println!("\ngenerating procedure {:?}\n", proc.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.append_proc_debug_name(proc.name.call_name());
|
self.append_proc_debug_name(proc.name.name());
|
||||||
|
|
||||||
self.start_proc(proc);
|
self.start_proc(proc);
|
||||||
|
|
||||||
|
@ -1125,9 +1125,10 @@ impl<'a> WasmBackend<'a> {
|
||||||
let proc_layout = ProcLayout {
|
let proc_layout = ProcLayout {
|
||||||
arguments: arg_layouts,
|
arguments: arg_layouts,
|
||||||
result: **result,
|
result: **result,
|
||||||
|
captures_niche: func_sym.captures_niche,
|
||||||
};
|
};
|
||||||
self.expr_call_by_name(
|
self.expr_call_by_name(
|
||||||
*func_sym,
|
func_sym.name(),
|
||||||
&proc_layout,
|
&proc_layout,
|
||||||
arguments,
|
arguments,
|
||||||
ret_sym,
|
ret_sym,
|
||||||
|
|
|
@ -1951,12 +1951,13 @@ pub fn call_higher_order_lowlevel<'a>(
|
||||||
let passed_proc_layout = ProcLayout {
|
let passed_proc_layout = ProcLayout {
|
||||||
arguments: argument_layouts,
|
arguments: argument_layouts,
|
||||||
result: *result_layout,
|
result: *result_layout,
|
||||||
|
captures_niche: fn_name.captures_niche,
|
||||||
};
|
};
|
||||||
let passed_proc_index = backend
|
let passed_proc_index = backend
|
||||||
.proc_lookup
|
.proc_lookup
|
||||||
.iter()
|
.iter()
|
||||||
.position(|ProcLookupData { name, layout, .. }| {
|
.position(|ProcLookupData { name, layout, .. }| {
|
||||||
name == fn_name && layout == &passed_proc_layout
|
*name == fn_name.name() && layout == &passed_proc_layout
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
ProcSource::HigherOrderWrapper(passed_proc_index)
|
ProcSource::HigherOrderWrapper(passed_proc_index)
|
||||||
|
@ -1984,6 +1985,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
||||||
ProcLayout {
|
ProcLayout {
|
||||||
arguments: wrapper_arg_layouts.into_bump_slice(),
|
arguments: wrapper_arg_layouts.into_bump_slice(),
|
||||||
result: Layout::UNIT,
|
result: Layout::UNIT,
|
||||||
|
captures_niche: &[],
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,7 @@ struct ModuleCache<'a> {
|
||||||
typechecked: MutMap<ModuleId, TypeCheckedModule<'a>>,
|
typechecked: MutMap<ModuleId, TypeCheckedModule<'a>>,
|
||||||
found_specializations: MutMap<ModuleId, FoundSpecializationsModule<'a>>,
|
found_specializations: MutMap<ModuleId, FoundSpecializationsModule<'a>>,
|
||||||
late_specializations: MutMap<ModuleId, LateSpecializationsModule<'a>>,
|
late_specializations: MutMap<ModuleId, LateSpecializationsModule<'a>>,
|
||||||
external_specializations_requested: MutMap<ModuleId, Vec<ExternalSpecializations>>,
|
external_specializations_requested: MutMap<ModuleId, Vec<ExternalSpecializations<'a>>>,
|
||||||
|
|
||||||
/// Various information
|
/// Various information
|
||||||
imports: MutMap<ModuleId, MutSet<ModuleId>>,
|
imports: MutMap<ModuleId, MutSet<ModuleId>>,
|
||||||
|
@ -717,7 +717,7 @@ enum Msg<'a> {
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
ident_ids: IdentIds,
|
ident_ids: IdentIds,
|
||||||
layout_cache: LayoutCache<'a>,
|
layout_cache: LayoutCache<'a>,
|
||||||
external_specializations_requested: BumpMap<ModuleId, ExternalSpecializations>,
|
external_specializations_requested: BumpMap<ModuleId, ExternalSpecializations<'a>>,
|
||||||
procs_base: ProcsBase<'a>,
|
procs_base: ProcsBase<'a>,
|
||||||
procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
|
procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||||
update_mode_ids: UpdateModeIds,
|
update_mode_ids: UpdateModeIds,
|
||||||
|
@ -1013,7 +1013,7 @@ enum BuildTask<'a> {
|
||||||
subs: Subs,
|
subs: Subs,
|
||||||
procs_base: ProcsBase<'a>,
|
procs_base: ProcsBase<'a>,
|
||||||
layout_cache: LayoutCache<'a>,
|
layout_cache: LayoutCache<'a>,
|
||||||
specializations_we_must_make: Vec<ExternalSpecializations>,
|
specializations_we_must_make: Vec<ExternalSpecializations<'a>>,
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
world_abilities: WorldAbilities,
|
world_abilities: WorldAbilities,
|
||||||
derived_symbols: GlobalDerivedSymbols,
|
derived_symbols: GlobalDerivedSymbols,
|
||||||
|
@ -2678,6 +2678,7 @@ fn finish_specialization(
|
||||||
layout: roc_mono::ir::ProcLayout {
|
layout: roc_mono::ir::ProcLayout {
|
||||||
arguments: &[],
|
arguments: &[],
|
||||||
result: Layout::struct_no_name_order(&[]),
|
result: Layout::struct_no_name_order(&[]),
|
||||||
|
captures_niche: &[],
|
||||||
},
|
},
|
||||||
symbol,
|
symbol,
|
||||||
}
|
}
|
||||||
|
@ -4425,7 +4426,7 @@ fn make_specializations<'a>(
|
||||||
mut subs: Subs,
|
mut subs: Subs,
|
||||||
procs_base: ProcsBase<'a>,
|
procs_base: ProcsBase<'a>,
|
||||||
mut layout_cache: LayoutCache<'a>,
|
mut layout_cache: LayoutCache<'a>,
|
||||||
specializations_we_must_make: Vec<ExternalSpecializations>,
|
specializations_we_must_make: Vec<ExternalSpecializations<'a>>,
|
||||||
mut module_timing: ModuleTiming,
|
mut module_timing: ModuleTiming,
|
||||||
target_info: TargetInfo,
|
target_info: TargetInfo,
|
||||||
world_abilities: WorldAbilities,
|
world_abilities: WorldAbilities,
|
||||||
|
|
|
@ -263,7 +263,7 @@ impl<'a> ParamMap<'a> {
|
||||||
self.declarations[index + i] = param;
|
self.declarations[index + i] = param;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.visit_stmt(arena, proc.name.call_name(), &proc.body);
|
self.visit_stmt(arena, proc.name.name(), &proc.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_proc_always_owned(
|
fn visit_proc_always_owned(
|
||||||
|
@ -282,7 +282,7 @@ impl<'a> ParamMap<'a> {
|
||||||
self.declarations[index + i] = param;
|
self.declarations[index + i] = param;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.visit_stmt(arena, proc.name.call_name(), &proc.body);
|
self.visit_stmt(arena, proc.name.name(), &proc.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_stmt(&mut self, arena: &'a Bump, _fnid: Symbol, stmt: &Stmt<'a>) {
|
fn visit_stmt(&mut self, arena: &'a Bump, _fnid: Symbol, stmt: &Stmt<'a>) {
|
||||||
|
@ -501,11 +501,12 @@ impl<'a> BorrowInfState<'a> {
|
||||||
arg_layouts,
|
arg_layouts,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let top_level = ProcLayout::new(self.arena, arg_layouts, **ret_layout);
|
let top_level =
|
||||||
|
ProcLayout::new(self.arena, arg_layouts, name.captures_niche, **ret_layout);
|
||||||
|
|
||||||
// get the borrow signature of the applied function
|
// get the borrow signature of the applied function
|
||||||
let ps = param_map
|
let ps = param_map
|
||||||
.get_symbol(*name, top_level)
|
.get_symbol(name.name(), top_level)
|
||||||
.expect("function is defined");
|
.expect("function is defined");
|
||||||
|
|
||||||
// the return value will be owned
|
// the return value will be owned
|
||||||
|
@ -544,12 +545,14 @@ impl<'a> BorrowInfState<'a> {
|
||||||
let closure_layout = ProcLayout {
|
let closure_layout = ProcLayout {
|
||||||
arguments: passed_function.argument_layouts,
|
arguments: passed_function.argument_layouts,
|
||||||
result: passed_function.return_layout,
|
result: passed_function.return_layout,
|
||||||
|
captures_niche: passed_function.name.captures_niche,
|
||||||
};
|
};
|
||||||
|
|
||||||
let function_ps = match param_map.get_symbol(passed_function.name, closure_layout) {
|
let function_ps =
|
||||||
Some(function_ps) => function_ps,
|
match param_map.get_symbol(passed_function.name.name(), closure_layout) {
|
||||||
None => unreachable!(),
|
Some(function_ps) => function_ps,
|
||||||
};
|
None => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
ListMap { xs } => {
|
ListMap { xs } => {
|
||||||
|
@ -743,12 +746,13 @@ impl<'a> BorrowInfState<'a> {
|
||||||
Stmt::Ret(z),
|
Stmt::Ret(z),
|
||||||
) = (v, b)
|
) = (v, b)
|
||||||
{
|
{
|
||||||
let top_level = ProcLayout::new(self.arena, arg_layouts, **ret_layout);
|
let top_level =
|
||||||
|
ProcLayout::new(self.arena, arg_layouts, g.captures_niche, **ret_layout);
|
||||||
|
|
||||||
if self.current_proc == *g && x == *z {
|
if self.current_proc == g.name() && x == *z {
|
||||||
// anonymous functions (for which the ps may not be known)
|
// anonymous functions (for which the ps may not be known)
|
||||||
// can never be tail-recursive, so this is fine
|
// can never be tail-recursive, so this is fine
|
||||||
if let Some(ps) = param_map.get_symbol(*g, top_level) {
|
if let Some(ps) = param_map.get_symbol(g.name(), top_level) {
|
||||||
self.own_params_using_args(ys, ps)
|
self.own_params_using_args(ys, ps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -852,10 +856,10 @@ impl<'a> BorrowInfState<'a> {
|
||||||
|
|
||||||
let ys = Vec::from_iter_in(proc.args.iter().map(|t| t.1), self.arena).into_bump_slice();
|
let ys = Vec::from_iter_in(proc.args.iter().map(|t| t.1), self.arena).into_bump_slice();
|
||||||
self.update_param_set_symbols(ys);
|
self.update_param_set_symbols(ys);
|
||||||
self.current_proc = proc.name.call_name();
|
self.current_proc = proc.name.name();
|
||||||
|
|
||||||
// ensure that current_proc is in the owned map
|
// ensure that current_proc is in the owned map
|
||||||
self.owned.entry(proc.name.call_name()).or_default();
|
self.owned.entry(proc.name.name()).or_default();
|
||||||
|
|
||||||
self.collect_stmt(param_map, &proc.body);
|
self.collect_stmt(param_map, &proc.body);
|
||||||
self.update_param_map_declaration(param_map, param_offset, proc.args.len());
|
self.update_param_map_declaration(param_map, param_offset, proc.args.len());
|
||||||
|
@ -975,7 +979,7 @@ fn call_info_call<'a>(call: &crate::ir::Call<'a>, info: &mut CallInfo<'a>) {
|
||||||
|
|
||||||
match call.call_type {
|
match call.call_type {
|
||||||
ByName { name, .. } => {
|
ByName { name, .. } => {
|
||||||
info.keys.push(name);
|
info.keys.push(name.name());
|
||||||
}
|
}
|
||||||
Foreign { .. } => {}
|
Foreign { .. } => {}
|
||||||
LowLevel { .. } => {}
|
LowLevel { .. } => {}
|
||||||
|
|
|
@ -170,7 +170,7 @@ impl<'a> CodeGenHelp<'a> {
|
||||||
let arg_layouts = self.arena.alloc([layout]);
|
let arg_layouts = self.arena.alloc([layout]);
|
||||||
let expr = Expr::Call(Call {
|
let expr = Expr::Call(Call {
|
||||||
call_type: CallType::ByName {
|
call_type: CallType::ByName {
|
||||||
name: proc_name,
|
name: LambdaName::only_receiver(proc_name),
|
||||||
ret_layout,
|
ret_layout,
|
||||||
arg_layouts,
|
arg_layouts,
|
||||||
specialization_id: CallSpecId::BACKEND_DUMMY,
|
specialization_id: CallSpecId::BACKEND_DUMMY,
|
||||||
|
@ -262,7 +262,7 @@ impl<'a> CodeGenHelp<'a> {
|
||||||
|
|
||||||
Some(Expr::Call(Call {
|
Some(Expr::Call(Call {
|
||||||
call_type: CallType::ByName {
|
call_type: CallType::ByName {
|
||||||
name: proc_name,
|
name: LambdaName::only_receiver(proc_name),
|
||||||
ret_layout,
|
ret_layout,
|
||||||
arg_layouts,
|
arg_layouts,
|
||||||
specialization_id: CallSpecId::BACKEND_DUMMY,
|
specialization_id: CallSpecId::BACKEND_DUMMY,
|
||||||
|
@ -375,19 +375,23 @@ impl<'a> CodeGenHelp<'a> {
|
||||||
HelperOp::Inc => ProcLayout {
|
HelperOp::Inc => ProcLayout {
|
||||||
arguments: self.arena.alloc([*layout, self.layout_isize]),
|
arguments: self.arena.alloc([*layout, self.layout_isize]),
|
||||||
result: LAYOUT_UNIT,
|
result: LAYOUT_UNIT,
|
||||||
|
captures_niche: &[],
|
||||||
},
|
},
|
||||||
HelperOp::Dec => ProcLayout {
|
HelperOp::Dec => ProcLayout {
|
||||||
arguments: self.arena.alloc([*layout]),
|
arguments: self.arena.alloc([*layout]),
|
||||||
result: LAYOUT_UNIT,
|
result: LAYOUT_UNIT,
|
||||||
|
captures_niche: &[],
|
||||||
},
|
},
|
||||||
HelperOp::Reset => ProcLayout {
|
HelperOp::Reset => ProcLayout {
|
||||||
arguments: self.arena.alloc([*layout]),
|
arguments: self.arena.alloc([*layout]),
|
||||||
result: *layout,
|
result: *layout,
|
||||||
|
captures_niche: &[],
|
||||||
},
|
},
|
||||||
HelperOp::DecRef(_) => unreachable!("No generated Proc for DecRef"),
|
HelperOp::DecRef(_) => unreachable!("No generated Proc for DecRef"),
|
||||||
HelperOp::Eq => ProcLayout {
|
HelperOp::Eq => ProcLayout {
|
||||||
arguments: self.arena.alloc([*layout, *layout]),
|
arguments: self.arena.alloc([*layout, *layout]),
|
||||||
result: LAYOUT_BOOL,
|
result: LAYOUT_BOOL,
|
||||||
|
captures_niche: &[],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -564,12 +564,13 @@ impl<'a> Context<'a> {
|
||||||
arg_layouts,
|
arg_layouts,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let top_level = ProcLayout::new(self.arena, arg_layouts, **ret_layout);
|
let top_level =
|
||||||
|
ProcLayout::new(self.arena, arg_layouts, name.captures_niche, **ret_layout);
|
||||||
|
|
||||||
// get the borrow signature
|
// get the borrow signature
|
||||||
let ps = self
|
let ps = self
|
||||||
.param_map
|
.param_map
|
||||||
.get_symbol(*name, top_level)
|
.get_symbol(name.name(), top_level)
|
||||||
.expect("function is defined");
|
.expect("function is defined");
|
||||||
|
|
||||||
let v = Expr::Call(crate::ir::Call {
|
let v = Expr::Call(crate::ir::Call {
|
||||||
|
@ -614,11 +615,12 @@ impl<'a> Context<'a> {
|
||||||
let function_layout = ProcLayout {
|
let function_layout = ProcLayout {
|
||||||
arguments: passed_function.argument_layouts,
|
arguments: passed_function.argument_layouts,
|
||||||
result: passed_function.return_layout,
|
result: passed_function.return_layout,
|
||||||
|
captures_niche: passed_function.name.captures_niche,
|
||||||
};
|
};
|
||||||
|
|
||||||
let function_ps = match self
|
let function_ps = match self
|
||||||
.param_map
|
.param_map
|
||||||
.get_symbol(passed_function.name, function_layout)
|
.get_symbol(passed_function.name.name(), function_layout)
|
||||||
{
|
{
|
||||||
Some(function_ps) => function_ps,
|
Some(function_ps) => function_ps,
|
||||||
None => unreachable!(),
|
None => unreachable!(),
|
||||||
|
@ -1406,7 +1408,7 @@ fn visit_proc<'a, 'i>(
|
||||||
proc: &mut Proc<'a>,
|
proc: &mut Proc<'a>,
|
||||||
layout: ProcLayout<'a>,
|
layout: ProcLayout<'a>,
|
||||||
) {
|
) {
|
||||||
let params = match param_map.get_symbol(proc.name.call_name(), layout) {
|
let params = match param_map.get_symbol(proc.name.name(), layout) {
|
||||||
Some(slice) => slice,
|
Some(slice) => slice,
|
||||||
None => Vec::from_iter_in(
|
None => Vec::from_iter_in(
|
||||||
proc.args.iter().cloned().map(|(layout, symbol)| Param {
|
proc.args.iter().cloned().map(|(layout, symbol)| Param {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -232,7 +232,7 @@ impl<'a> RawFunctionLayout<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct FieldOrderHash(u64);
|
pub struct FieldOrderHash(u64);
|
||||||
|
|
||||||
impl FieldOrderHash {
|
impl FieldOrderHash {
|
||||||
|
@ -254,7 +254,7 @@ impl FieldOrderHash {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Types for code gen must be monomorphic. No type variables allowed!
|
/// Types for code gen must be monomorphic. No type variables allowed!
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub enum Layout<'a> {
|
pub enum Layout<'a> {
|
||||||
Builtin(Builtin<'a>),
|
Builtin(Builtin<'a>),
|
||||||
Struct {
|
Struct {
|
||||||
|
@ -276,7 +276,7 @@ pub enum Layout<'a> {
|
||||||
RecursivePointer,
|
RecursivePointer,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub enum UnionLayout<'a> {
|
pub enum UnionLayout<'a> {
|
||||||
/// A non-recursive tag union
|
/// A non-recursive tag union
|
||||||
/// e.g. `Result a e : [Ok a, Err e]`
|
/// e.g. `Result a e : [Ok a, Err e]`
|
||||||
|
@ -678,16 +678,13 @@ impl std::fmt::Debug for SetElement<'_> {
|
||||||
impl std::fmt::Debug for LambdaSet<'_> {
|
impl std::fmt::Debug for LambdaSet<'_> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
struct Helper<'a> {
|
struct Helper<'a> {
|
||||||
set: &'a [(LambdaName, &'a [Layout<'a>])],
|
set: &'a [(Symbol, &'a [Layout<'a>])],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for Helper<'_> {
|
impl std::fmt::Debug for Helper<'_> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let entries = self.set.iter().map(|x| SetElement {
|
let entries = self.set.iter().map(|x| SetElement {
|
||||||
symbol: match (x.0).0 {
|
symbol: x.0,
|
||||||
LambdaNameInner::Name(name) => name,
|
|
||||||
LambdaNameInner::Multimorphic { alias, .. } => alias,
|
|
||||||
},
|
|
||||||
layout: x.1,
|
layout: x.1,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -864,74 +861,61 @@ impl MultimorphicNames {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static_assertions::assert_eq_size!(&[Layout], Option<&[Layout]>);
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
enum LambdaNameInner {
|
pub struct LambdaName<'a> {
|
||||||
/// Standard lambda name assigned during canonicalize/constrain
|
name: Symbol,
|
||||||
Name(Symbol),
|
|
||||||
/// Sometimes we can end up with lambdas of the same name and different captures in the same
|
/// Sometimes we can end up with lambdas of the same name and different captures in the same
|
||||||
/// lambda set, like [[Thunk U8, Thunk Str]]. See also https://github.com/rtfeldman/roc/issues/3336.
|
/// lambda set, like [[Thunk U8, Thunk Str]]. See also https://github.com/rtfeldman/roc/issues/3336.
|
||||||
/// We call such lambdas "multi-morphic".
|
|
||||||
///
|
///
|
||||||
/// The current compilation scheme in such cases is to assign an alias name for subsequent such
|
/// By recording the captures layouts this lambda expects in its identifier, we can distinguish
|
||||||
/// lambda names, and then code-gen those lambda variants under a different `Proc`. In our
|
/// between such differences.
|
||||||
/// example, the lambda set would be transformed to something like
|
pub captures_niche: &'a [Layout<'a>],
|
||||||
/// [[Thunk U8, Multimorphic(Thunk, ThunkAliasStr) Str]] which tells us to specialize the
|
|
||||||
/// second variant using the proc `Thunk` but under the name `ThunkAliasStr`, with that
|
|
||||||
/// particular closure layout.
|
|
||||||
///
|
|
||||||
/// Currently we do no de-duplication of alias names. This does make compilation faster, but
|
|
||||||
/// also we should expect redundant multimorphic aliases to be somewhat rare, as that means a
|
|
||||||
/// non-unitary lambda set is the same in multiple areas of a program.
|
|
||||||
Multimorphic {
|
|
||||||
/// The lambda we came from, e.g. `Thunk` in the example
|
|
||||||
source: Symbol,
|
|
||||||
/// The lambda we become, e.g. `ThunkAliasStr` in the example
|
|
||||||
alias: Symbol,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
impl LambdaName<'_> {
|
||||||
pub struct LambdaName(LambdaNameInner);
|
|
||||||
|
|
||||||
impl LambdaName {
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn source_name(&self) -> Symbol {
|
pub fn name(&self) -> Symbol {
|
||||||
match self.0 {
|
self.name
|
||||||
LambdaNameInner::Name(name) => name,
|
|
||||||
LambdaNameInner::Multimorphic { source, .. } => source,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn call_name(&self) -> Symbol {
|
pub fn no_captures(&self) -> bool {
|
||||||
match self.0 {
|
self.captures_niche.is_empty()
|
||||||
LambdaNameInner::Name(name) => name,
|
|
||||||
LambdaNameInner::Multimorphic { alias, .. } => alias,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_multimorphic(&self) -> bool {
|
|
||||||
matches!(self.0, LambdaNameInner::Multimorphic { .. })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn thunk(name: Symbol) -> Self {
|
pub fn thunk(name: Symbol) -> Self {
|
||||||
Self(LambdaNameInner::Name(name))
|
Self {
|
||||||
|
name,
|
||||||
|
captures_niche: &[],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the function name is known, so there can only be one possible receiver, in such cases
|
// When the function name is known, so there can only be one possible receiver, in such cases
|
||||||
// the lambda cannot be multimorphic.
|
// the lambda cannot be multimorphic.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn only_receiver(name: Symbol) -> Self {
|
pub fn only_receiver(name: Symbol) -> Self {
|
||||||
Self(LambdaNameInner::Name(name))
|
Self {
|
||||||
|
name,
|
||||||
|
captures_niche: &[],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn replace_name(&self, name: Symbol) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
captures_niche: self.captures_niche,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct LambdaSet<'a> {
|
pub struct LambdaSet<'a> {
|
||||||
/// collection of function names and their closure arguments
|
/// collection of function names and their closure arguments
|
||||||
pub set: &'a [(LambdaName, &'a [Layout<'a>])],
|
pub set: &'a [(Symbol, &'a [Layout<'a>])],
|
||||||
/// how the closure will be represented at runtime
|
/// how the closure will be represented at runtime
|
||||||
representation: &'a Layout<'a>,
|
representation: &'a Layout<'a>,
|
||||||
}
|
}
|
||||||
|
@ -961,12 +945,8 @@ impl<'a> LambdaSet<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Does the lambda set contain the given symbol?
|
/// Does the lambda set contain the given symbol?
|
||||||
/// NOTE: for multimorphic variants, this checks the alias name.
|
|
||||||
pub fn contains(&self, symbol: Symbol) -> bool {
|
pub fn contains(&self, symbol: Symbol) -> bool {
|
||||||
self.set.iter().any(|(s, _)| match s.0 {
|
self.set.iter().any(|(s, _)| *s == symbol)
|
||||||
LambdaNameInner::Name(name) => name == symbol,
|
|
||||||
LambdaNameInner::Multimorphic { alias, .. } => alias == symbol,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_represented(&self) -> Option<Layout<'a>> {
|
pub fn is_represented(&self) -> Option<Layout<'a>> {
|
||||||
|
@ -980,64 +960,54 @@ impl<'a> LambdaSet<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn iter_set(&self) -> impl ExactSizeIterator<Item = LambdaName<'a>> {
|
||||||
|
self.set.iter().map(|(name, captures_layouts)| LambdaName {
|
||||||
|
name: *name,
|
||||||
|
captures_niche: captures_layouts,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn layout_for_member_with_lambda_name(
|
pub fn layout_for_member_with_lambda_name(
|
||||||
&self,
|
&self,
|
||||||
lambda_name: LambdaName,
|
lambda_name: LambdaName,
|
||||||
) -> ClosureRepresentation<'a> {
|
) -> ClosureRepresentation<'a> {
|
||||||
debug_assert!(
|
debug_assert!(self.contains(lambda_name.name));
|
||||||
self.set.iter().any(|(s, _)| *s == lambda_name),
|
|
||||||
"lambda {:?} not in set {:#?}",
|
|
||||||
lambda_name,
|
|
||||||
self.set,
|
|
||||||
);
|
|
||||||
|
|
||||||
let comparator =
|
let comparator = |other_name: Symbol, other_captures_layouts: &[Layout]| {
|
||||||
|other_name: LambdaName, _other_captures_layouts: &[Layout]| other_name == lambda_name;
|
other_name == lambda_name.name
|
||||||
|
&& other_captures_layouts.iter().eq(lambda_name.captures_niche)
|
||||||
|
};
|
||||||
|
|
||||||
self.layout_for_member(comparator)
|
self.layout_for_member(comparator)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains_source(&self, symbol: Symbol) -> bool {
|
|
||||||
self.set.iter().any(|(s, _)| match s.0 {
|
|
||||||
LambdaNameInner::Name(name) => name == symbol,
|
|
||||||
LambdaNameInner::Multimorphic { source, .. } => source == symbol,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Finds an alias name for a possible-multimorphic lambda variant in the lambda set.
|
/// Finds an alias name for a possible-multimorphic lambda variant in the lambda set.
|
||||||
pub fn find_lambda_name(
|
pub fn find_lambda_name(
|
||||||
&self,
|
&self,
|
||||||
function_symbol: Symbol,
|
function_symbol: Symbol,
|
||||||
captures_layouts: &[Layout],
|
captures_layouts: &[Layout],
|
||||||
) -> LambdaName {
|
) -> LambdaName<'a> {
|
||||||
debug_assert!(
|
debug_assert!(self.contains(function_symbol), "function symbol not in set");
|
||||||
self.contains_source(function_symbol),
|
|
||||||
"function symbol not in set"
|
|
||||||
);
|
|
||||||
|
|
||||||
let comparator = |other_name: LambdaName, other_captures_layouts: &[Layout]| {
|
let comparator = |other_name: Symbol, other_captures_layouts: &[Layout]| {
|
||||||
let other_name = match other_name.0 {
|
other_name == function_symbol && other_captures_layouts.iter().eq(captures_layouts)
|
||||||
LambdaNameInner::Name(name) => name,
|
|
||||||
// Take the source, since we'll want to pick out the multimorphic name if it
|
|
||||||
// matches
|
|
||||||
LambdaNameInner::Multimorphic { source, .. } => source,
|
|
||||||
};
|
|
||||||
other_name == function_symbol
|
|
||||||
&& captures_layouts.iter().eq(other_captures_layouts.iter())
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let (name, _) = self
|
let (name, layouts) = self
|
||||||
.set
|
.set
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(name, layouts)| comparator(*name, layouts))
|
.find(|(name, layouts)| comparator(*name, layouts))
|
||||||
.expect("no lambda set found");
|
.expect("no lambda set found");
|
||||||
|
|
||||||
*name
|
LambdaName {
|
||||||
|
name: *name,
|
||||||
|
captures_niche: layouts,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout_for_member<F>(&self, comparator: F) -> ClosureRepresentation<'a>
|
fn layout_for_member<F>(&self, comparator: F) -> ClosureRepresentation<'a>
|
||||||
where
|
where
|
||||||
F: Fn(LambdaName, &[Layout]) -> bool,
|
F: Fn(Symbol, &[Layout]) -> bool,
|
||||||
{
|
{
|
||||||
match self.representation {
|
match self.representation {
|
||||||
Layout::Union(union) => {
|
Layout::Union(union) => {
|
||||||
|
@ -1054,10 +1024,7 @@ impl<'a> LambdaSet<'a> {
|
||||||
.find(|(_, (s, layouts))| comparator(*s, layouts))
|
.find(|(_, (s, layouts))| comparator(*s, layouts))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let closure_name = match name.0 {
|
let closure_name = *name;
|
||||||
LambdaNameInner::Name(name) => name,
|
|
||||||
LambdaNameInner::Multimorphic { alias, .. } => alias,
|
|
||||||
};
|
|
||||||
|
|
||||||
ClosureRepresentation::Union {
|
ClosureRepresentation::Union {
|
||||||
tag_id: index as TagIdIntType,
|
tag_id: index as TagIdIntType,
|
||||||
|
@ -1140,15 +1107,14 @@ impl<'a> LambdaSet<'a> {
|
||||||
// sort the tags; make sure ordering stays intact!
|
// sort the tags; make sure ordering stays intact!
|
||||||
lambdas.sort_by_key(|(sym, _)| *sym);
|
lambdas.sort_by_key(|(sym, _)| *sym);
|
||||||
|
|
||||||
let mut set: Vec<(LambdaName, &[Layout])> =
|
let mut set: Vec<(Symbol, &[Layout])> = Vec::with_capacity_in(lambdas.len(), arena);
|
||||||
Vec::with_capacity_in(lambdas.len(), arena);
|
let mut set_with_variables: std::vec::Vec<(Symbol, std::vec::Vec<Variable>)> =
|
||||||
let mut set_for_making_repr: std::vec::Vec<(Symbol, std::vec::Vec<Variable>)> =
|
|
||||||
std::vec::Vec::with_capacity(lambdas.len());
|
std::vec::Vec::with_capacity(lambdas.len());
|
||||||
|
|
||||||
let mut last_function_symbol = None;
|
let mut last_function_symbol = None;
|
||||||
let mut lambdas_it = lambdas.iter().peekable();
|
let mut lambdas_it = lambdas.iter().peekable();
|
||||||
|
|
||||||
let mut has_multimorphic = false;
|
let mut has_duplicate_lambda_names = false;
|
||||||
while let Some((function_symbol, variables)) = lambdas_it.next() {
|
while let Some((function_symbol, variables)) = lambdas_it.next() {
|
||||||
let mut arguments = Vec::with_capacity_in(variables.len(), arena);
|
let mut arguments = Vec::with_capacity_in(variables.len(), arena);
|
||||||
|
|
||||||
|
@ -1174,37 +1140,42 @@ impl<'a> LambdaSet<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let lambda_name = if is_multimorphic {
|
has_duplicate_lambda_names = has_duplicate_lambda_names || is_multimorphic;
|
||||||
let alias = multimorphic_names.get_or_insert(*function_symbol, arguments);
|
|
||||||
|
|
||||||
has_multimorphic = true;
|
set.push((*function_symbol, arguments));
|
||||||
|
set_with_variables.push((*function_symbol, variables.to_vec()));
|
||||||
LambdaNameInner::Multimorphic {
|
|
||||||
source: *function_symbol,
|
|
||||||
alias,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LambdaNameInner::Name(*function_symbol)
|
|
||||||
};
|
|
||||||
let lambda_name = LambdaName(lambda_name);
|
|
||||||
|
|
||||||
set.push((lambda_name, arguments));
|
|
||||||
set_for_making_repr.push((lambda_name.call_name(), variables.to_vec()));
|
|
||||||
|
|
||||||
last_function_symbol = Some(function_symbol);
|
last_function_symbol = Some(function_symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_multimorphic {
|
let (set, set_with_variables) = if has_duplicate_lambda_names {
|
||||||
// Must re-sort the set in case we added multimorphic lambdas since they may under
|
// If we have a lambda set with duplicate names, then we sort first by name,
|
||||||
// another name
|
// and break ties by sorting on the layout. We need to do this again since the
|
||||||
set.sort_by_key(|(name, _)| name.call_name());
|
// first sort would not have sorted on the layout.
|
||||||
set_for_making_repr.sort_by_key(|(name, _)| *name);
|
|
||||||
}
|
// TODO: be more efficient, we can compute the permutation once and then apply
|
||||||
|
// it to both vectors.
|
||||||
|
let mut joined = set
|
||||||
|
.into_iter()
|
||||||
|
.zip(set_with_variables.into_iter())
|
||||||
|
.collect::<std::vec::Vec<_>>();
|
||||||
|
joined.sort_by(|(lam_and_captures1, _), (lam_and_captures2, _)| {
|
||||||
|
lam_and_captures1.cmp(lam_and_captures2)
|
||||||
|
});
|
||||||
|
let (set, set_with_variables): (std::vec::Vec<_>, std::vec::Vec<_>) =
|
||||||
|
joined.into_iter().unzip();
|
||||||
|
|
||||||
|
let set = Vec::from_iter_in(set, arena);
|
||||||
|
|
||||||
|
(set, set_with_variables)
|
||||||
|
} else {
|
||||||
|
(set, set_with_variables)
|
||||||
|
};
|
||||||
|
|
||||||
let representation = arena.alloc(Self::make_representation(
|
let representation = arena.alloc(Self::make_representation(
|
||||||
arena,
|
arena,
|
||||||
subs,
|
subs,
|
||||||
set_for_making_repr,
|
set_with_variables,
|
||||||
target_info,
|
target_info,
|
||||||
multimorphic_names,
|
multimorphic_names,
|
||||||
));
|
));
|
||||||
|
@ -1323,7 +1294,7 @@ fn resolve_lambda_set(subs: &Subs, mut var: Variable) -> ResolvedLambdaSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub enum Builtin<'a> {
|
pub enum Builtin<'a> {
|
||||||
Int(IntWidth),
|
Int(IntWidth),
|
||||||
Float(FloatWidth),
|
Float(FloatWidth),
|
||||||
|
@ -3433,7 +3404,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn width_and_alignment_union_empty_struct() {
|
fn width_and_alignment_union_empty_struct() {
|
||||||
let lambda_set = LambdaSet {
|
let lambda_set = LambdaSet {
|
||||||
set: &[(LambdaName::only_receiver(Symbol::LIST_MAP), &[])],
|
set: &[(Symbol::LIST_MAP, &[])],
|
||||||
representation: &Layout::UNIT,
|
representation: &Layout::UNIT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#![allow(clippy::manual_map)]
|
#![allow(clippy::manual_map)]
|
||||||
|
|
||||||
use crate::ir::{CallType, Expr, JoinPointId, Param, Stmt};
|
use crate::ir::{CallType, Expr, JoinPointId, Param, Stmt};
|
||||||
use crate::layout::Layout;
|
use crate::layout::{LambdaName, Layout};
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
|
@ -31,7 +31,7 @@ use roc_module::symbol::Symbol;
|
||||||
pub fn make_tail_recursive<'a>(
|
pub fn make_tail_recursive<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
id: JoinPointId,
|
id: JoinPointId,
|
||||||
needle: Symbol,
|
needle: LambdaName,
|
||||||
stmt: Stmt<'a>,
|
stmt: Stmt<'a>,
|
||||||
args: &'a [(Layout<'a>, Symbol, Symbol)],
|
args: &'a [(Layout<'a>, Symbol, Symbol)],
|
||||||
ret_layout: Layout,
|
ret_layout: Layout,
|
||||||
|
@ -71,7 +71,7 @@ fn insert_jumps<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
stmt: &'a Stmt<'a>,
|
stmt: &'a Stmt<'a>,
|
||||||
goal_id: JoinPointId,
|
goal_id: JoinPointId,
|
||||||
needle: Symbol,
|
needle: LambdaName,
|
||||||
needle_arguments: &'a [(Layout<'a>, Symbol, Symbol)],
|
needle_arguments: &'a [(Layout<'a>, Symbol, Symbol)],
|
||||||
needle_result: Layout,
|
needle_result: Layout,
|
||||||
) -> Option<&'a Stmt<'a>> {
|
) -> Option<&'a Stmt<'a>> {
|
||||||
|
@ -80,7 +80,7 @@ fn insert_jumps<'a>(
|
||||||
// to insert a tail-call, it must not just be a call to the function itself, but it must also
|
// to insert a tail-call, it must not just be a call to the function itself, but it must also
|
||||||
// have the same layout. In particular when lambda sets get involved, a self-recursive call may
|
// have the same layout. In particular when lambda sets get involved, a self-recursive call may
|
||||||
// have a different type and should not be converted to a jump!
|
// have a different type and should not be converted to a jump!
|
||||||
let is_equal_function = |function_name: Symbol, arguments: &[_], result| {
|
let is_equal_function = |function_name: LambdaName, arguments: &[_], result| {
|
||||||
let it = needle_arguments.iter().map(|t| &t.0);
|
let it = needle_arguments.iter().map(|t| &t.0);
|
||||||
needle == function_name && it.eq(arguments.iter()) && needle_result == result
|
needle == function_name && it.eq(arguments.iter()) && needle_result == result
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,24 +1,29 @@
|
||||||
procedure #Multimorphic.0 (Test.23, #Attr.12):
|
procedure Num.94 (#Attr.2):
|
||||||
let Test.4 : Str = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
let Num.273 : Str = lowlevel NumToStr #Attr.2;
|
||||||
inc Test.4;
|
ret Num.273;
|
||||||
dec #Attr.12;
|
|
||||||
let Test.25 : Str = "";
|
|
||||||
ret Test.25;
|
|
||||||
|
|
||||||
procedure #Multimorphic.1 (Test.17, #Attr.12):
|
procedure Num.94 (#Attr.2):
|
||||||
let Test.4 : {} = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
let Num.274 : Str = lowlevel NumToStr #Attr.2;
|
||||||
dec #Attr.12;
|
ret Num.274;
|
||||||
let Test.19 : Str = "";
|
|
||||||
ret Test.19;
|
|
||||||
|
|
||||||
procedure Test.1 (Test.4):
|
procedure Test.1 (Test.4):
|
||||||
let Test.16 : [C Str, C {}] = ClosureTag(#Multimorphic.1) Test.4;
|
let Test.16 : [C U8, C U64] = ClosureTag(Test.5) Test.4;
|
||||||
ret Test.16;
|
ret Test.16;
|
||||||
|
|
||||||
procedure Test.1 (Test.4):
|
procedure Test.1 (Test.4):
|
||||||
let Test.22 : [C Str, C {}] = ClosureTag(#Multimorphic.0) Test.4;
|
let Test.22 : [C U8, C U64] = ClosureTag(Test.5) Test.4;
|
||||||
ret Test.22;
|
ret Test.22;
|
||||||
|
|
||||||
|
procedure Test.5 (Test.17, #Attr.12):
|
||||||
|
let Test.4 : U64 = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||||
|
let Test.19 : Str = CallByName Num.94 Test.4;
|
||||||
|
ret Test.19;
|
||||||
|
|
||||||
|
procedure Test.5 (Test.17, #Attr.12):
|
||||||
|
let Test.4 : U8 = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
||||||
|
let Test.25 : Str = CallByName Num.94 Test.4;
|
||||||
|
ret Test.25;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.2 : Int1 = true;
|
let Test.2 : Int1 = true;
|
||||||
joinpoint Test.13 Test.3:
|
joinpoint Test.13 Test.3:
|
||||||
|
@ -29,21 +34,21 @@ procedure Test.0 ():
|
||||||
in
|
in
|
||||||
switch Test.9:
|
switch Test.9:
|
||||||
case 0:
|
case 0:
|
||||||
let Test.11 : Str = CallByName #Multimorphic.0 Test.8 Test.3;
|
let Test.11 : Str = CallByName Test.5 Test.8 Test.3;
|
||||||
jump Test.10 Test.11;
|
jump Test.10 Test.11;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
let Test.12 : Str = CallByName #Multimorphic.1 Test.8 Test.3;
|
let Test.12 : Str = CallByName Test.5 Test.8 Test.3;
|
||||||
jump Test.10 Test.12;
|
jump Test.10 Test.12;
|
||||||
|
|
||||||
in
|
in
|
||||||
let Test.26 : Int1 = true;
|
let Test.26 : Int1 = true;
|
||||||
let Test.27 : Int1 = lowlevel Eq Test.26 Test.2;
|
let Test.27 : Int1 = lowlevel Eq Test.26 Test.2;
|
||||||
if Test.27 then
|
if Test.27 then
|
||||||
let Test.15 : {} = Struct {};
|
let Test.15 : U64 = 123i64;
|
||||||
let Test.14 : [C Str, C {}] = CallByName Test.1 Test.15;
|
let Test.14 : [C U8, C U64] = CallByName Test.1 Test.15;
|
||||||
jump Test.13 Test.14;
|
jump Test.13 Test.14;
|
||||||
else
|
else
|
||||||
let Test.21 : Str = "";
|
let Test.21 : U8 = 18i64;
|
||||||
let Test.20 : [C Str, C {}] = CallByName Test.1 Test.21;
|
let Test.20 : [C U8, C U64] = CallByName Test.1 Test.21;
|
||||||
jump Test.13 Test.20;
|
jump Test.13 Test.20;
|
||||||
|
|
|
@ -1,24 +1,3 @@
|
||||||
procedure #Multimorphic.0 (Test.29, #Attr.12):
|
|
||||||
let Test.8 : {} = UnionAtIndex (Id 0) (Index 1) #Attr.12;
|
|
||||||
let Test.7 : {} = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
|
||||||
let Test.49 : {} = Struct {};
|
|
||||||
let Test.48 : Str = CallByName Test.16 Test.49;
|
|
||||||
let Test.45 : {Str} = CallByName Test.4 Test.48;
|
|
||||||
let Test.47 : {} = Struct {};
|
|
||||||
let Test.46 : Str = CallByName Test.13 Test.47 Test.45;
|
|
||||||
ret Test.46;
|
|
||||||
|
|
||||||
procedure #Multimorphic.1 (Test.29, #Attr.12):
|
|
||||||
let Test.8 : {} = UnionAtIndex (Id 1) (Index 1) #Attr.12;
|
|
||||||
let Test.7 : {} = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
|
||||||
let Test.35 : {} = Struct {};
|
|
||||||
let Test.34 : Str = CallByName Test.15 Test.35;
|
|
||||||
let Test.31 : {} = CallByName Test.3 Test.34;
|
|
||||||
dec Test.34;
|
|
||||||
let Test.33 : {} = Struct {};
|
|
||||||
let Test.32 : Str = CallByName Test.11 Test.33;
|
|
||||||
ret Test.32;
|
|
||||||
|
|
||||||
procedure Test.11 (Test.37):
|
procedure Test.11 (Test.37):
|
||||||
let Test.38 : Str = "";
|
let Test.38 : Str = "";
|
||||||
ret Test.38;
|
ret Test.38;
|
||||||
|
@ -38,11 +17,11 @@ procedure Test.16 (Test.54):
|
||||||
ret Test.56;
|
ret Test.56;
|
||||||
|
|
||||||
procedure Test.2 (Test.7, Test.8):
|
procedure Test.2 (Test.7, Test.8):
|
||||||
let Test.9 : [C {} {}, C {} {}] = ClosureTag(#Multimorphic.0) Test.7 Test.8;
|
let Test.9 : [C {} {}, C {} {}] = ClosureTag(Test.9) Test.7 Test.8;
|
||||||
ret Test.9;
|
ret Test.9;
|
||||||
|
|
||||||
procedure Test.2 (Test.7, Test.8):
|
procedure Test.2 (Test.7, Test.8):
|
||||||
let Test.9 : [C {} {}, C {} {}] = ClosureTag(#Multimorphic.1) Test.7 Test.8;
|
let Test.9 : [C {} {}, C {} {}] = ClosureTag(Test.9) Test.7 Test.8;
|
||||||
ret Test.9;
|
ret Test.9;
|
||||||
|
|
||||||
procedure Test.3 (Test.17):
|
procedure Test.3 (Test.17):
|
||||||
|
@ -53,6 +32,27 @@ procedure Test.4 (Test.18):
|
||||||
let Test.50 : {Str} = Struct {Test.18};
|
let Test.50 : {Str} = Struct {Test.18};
|
||||||
ret Test.50;
|
ret Test.50;
|
||||||
|
|
||||||
|
procedure Test.9 (Test.29, #Attr.12):
|
||||||
|
let Test.8 : {} = UnionAtIndex (Id 0) (Index 1) #Attr.12;
|
||||||
|
let Test.7 : {} = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
||||||
|
let Test.35 : {} = Struct {};
|
||||||
|
let Test.34 : Str = CallByName Test.15 Test.35;
|
||||||
|
let Test.31 : {} = CallByName Test.3 Test.34;
|
||||||
|
dec Test.34;
|
||||||
|
let Test.33 : {} = Struct {};
|
||||||
|
let Test.32 : Str = CallByName Test.11 Test.33;
|
||||||
|
ret Test.32;
|
||||||
|
|
||||||
|
procedure Test.9 (Test.29, #Attr.12):
|
||||||
|
let Test.8 : {} = UnionAtIndex (Id 1) (Index 1) #Attr.12;
|
||||||
|
let Test.7 : {} = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||||
|
let Test.49 : {} = Struct {};
|
||||||
|
let Test.48 : Str = CallByName Test.16 Test.49;
|
||||||
|
let Test.45 : {Str} = CallByName Test.4 Test.48;
|
||||||
|
let Test.47 : {} = Struct {};
|
||||||
|
let Test.46 : Str = CallByName Test.13 Test.47 Test.45;
|
||||||
|
ret Test.46;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.5 : Int1 = true;
|
let Test.5 : Int1 = true;
|
||||||
joinpoint Test.25 Test.6:
|
joinpoint Test.25 Test.6:
|
||||||
|
@ -63,11 +63,11 @@ procedure Test.0 ():
|
||||||
in
|
in
|
||||||
switch Test.21:
|
switch Test.21:
|
||||||
case 0:
|
case 0:
|
||||||
let Test.23 : Str = CallByName #Multimorphic.0 Test.20 Test.6;
|
let Test.23 : Str = CallByName Test.9 Test.20 Test.6;
|
||||||
jump Test.22 Test.23;
|
jump Test.22 Test.23;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
let Test.24 : Str = CallByName #Multimorphic.1 Test.20 Test.6;
|
let Test.24 : Str = CallByName Test.9 Test.20 Test.6;
|
||||||
jump Test.22 Test.24;
|
jump Test.22 Test.24;
|
||||||
|
|
||||||
in
|
in
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
procedure #Multimorphic.0 (Test.28, #Attr.12):
|
|
||||||
let Test.5 : U64 = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
|
||||||
let Test.30 : Str = "";
|
|
||||||
ret Test.30;
|
|
||||||
|
|
||||||
procedure #Multimorphic.1 (Test.20, #Attr.12):
|
|
||||||
let Test.5 : {} = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
|
||||||
let Test.22 : Str = "";
|
|
||||||
ret Test.22;
|
|
||||||
|
|
||||||
procedure Test.1 (Test.5):
|
procedure Test.1 (Test.5):
|
||||||
let Test.19 : [C U64, C {}, C ] = ClosureTag(#Multimorphic.1) Test.5;
|
let Test.19 : [C , C U64, C {}] = ClosureTag(Test.6) Test.5;
|
||||||
ret Test.19;
|
ret Test.19;
|
||||||
|
|
||||||
procedure Test.1 (Test.5):
|
procedure Test.1 (Test.5):
|
||||||
let Test.27 : [C U64, C {}, C ] = ClosureTag(#Multimorphic.0) Test.5;
|
let Test.27 : [C , C U64, C {}] = ClosureTag(Test.6) Test.5;
|
||||||
ret Test.27;
|
ret Test.27;
|
||||||
|
|
||||||
procedure Test.2 (Test.8):
|
procedure Test.2 (Test.8):
|
||||||
let Test.24 : Str = "";
|
let Test.24 : Str = "";
|
||||||
ret Test.24;
|
ret Test.24;
|
||||||
|
|
||||||
|
procedure Test.6 (Test.20, #Attr.12):
|
||||||
|
let Test.5 : U64 = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||||
|
let Test.30 : Str = "";
|
||||||
|
ret Test.30;
|
||||||
|
|
||||||
|
procedure Test.6 (Test.20, #Attr.12):
|
||||||
|
let Test.5 : {} = UnionAtIndex (Id 2) (Index 0) #Attr.12;
|
||||||
|
let Test.22 : Str = "";
|
||||||
|
ret Test.22;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.3 : U8 = 0u8;
|
let Test.3 : U8 = 0u8;
|
||||||
joinpoint Test.16 Test.4:
|
joinpoint Test.16 Test.4:
|
||||||
|
@ -30,30 +30,30 @@ procedure Test.0 ():
|
||||||
in
|
in
|
||||||
switch Test.11:
|
switch Test.11:
|
||||||
case 0:
|
case 0:
|
||||||
let Test.13 : Str = CallByName #Multimorphic.0 Test.10 Test.4;
|
let Test.13 : Str = CallByName Test.2 Test.10;
|
||||||
jump Test.12 Test.13;
|
jump Test.12 Test.13;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
let Test.14 : Str = CallByName #Multimorphic.1 Test.10 Test.4;
|
let Test.14 : Str = CallByName Test.6 Test.10 Test.4;
|
||||||
jump Test.12 Test.14;
|
jump Test.12 Test.14;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
let Test.15 : Str = CallByName Test.2 Test.10;
|
let Test.15 : Str = CallByName Test.6 Test.10 Test.4;
|
||||||
jump Test.12 Test.15;
|
jump Test.12 Test.15;
|
||||||
|
|
||||||
in
|
in
|
||||||
switch Test.3:
|
switch Test.3:
|
||||||
case 0:
|
case 0:
|
||||||
let Test.18 : {} = Struct {};
|
let Test.18 : {} = Struct {};
|
||||||
let Test.17 : [C U64, C {}, C ] = CallByName Test.1 Test.18;
|
let Test.17 : [C , C U64, C {}] = CallByName Test.1 Test.18;
|
||||||
jump Test.16 Test.17;
|
jump Test.16 Test.17;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
let Test.2 : [C U64, C {}, C ] = ClosureTag(Test.2) ;
|
let Test.2 : [C , C U64, C {}] = ClosureTag(Test.2) ;
|
||||||
jump Test.16 Test.2;
|
jump Test.16 Test.2;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
let Test.26 : U64 = 1i64;
|
let Test.26 : U64 = 1i64;
|
||||||
let Test.25 : [C U64, C {}, C ] = CallByName Test.1 Test.26;
|
let Test.25 : [C , C U64, C {}] = CallByName Test.1 Test.26;
|
||||||
jump Test.16 Test.25;
|
jump Test.16 Test.25;
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
procedure #Multimorphic.0 (Test.33, #Attr.12):
|
|
||||||
let Test.5 : U64 = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
|
||||||
dec #Attr.12;
|
|
||||||
let Test.35 : Str = "";
|
|
||||||
ret Test.35;
|
|
||||||
|
|
||||||
procedure #Multimorphic.1 (Test.21, #Attr.12):
|
|
||||||
let Test.5 : {} = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
|
||||||
dec #Attr.12;
|
|
||||||
let Test.23 : Str = "";
|
|
||||||
ret Test.23;
|
|
||||||
|
|
||||||
procedure Test.1 (Test.5):
|
procedure Test.1 (Test.5):
|
||||||
let Test.20 : [C U64, C {}, C Str] = ClosureTag(#Multimorphic.1) Test.5;
|
let Test.20 : [C U64, C {}, C Str] = ClosureTag(Test.6) Test.5;
|
||||||
ret Test.20;
|
ret Test.20;
|
||||||
|
|
||||||
procedure Test.1 (Test.5):
|
procedure Test.1 (Test.5):
|
||||||
let Test.32 : [C U64, C {}, C Str] = ClosureTag(#Multimorphic.0) Test.5;
|
let Test.32 : [C U64, C {}, C Str] = ClosureTag(Test.6) Test.5;
|
||||||
ret Test.32;
|
ret Test.32;
|
||||||
|
|
||||||
procedure Test.2 (Test.7):
|
procedure Test.2 (Test.7):
|
||||||
let Test.26 : [C U64, C {}, C Str] = ClosureTag(Test.8) Test.7;
|
let Test.26 : [C U64, C {}, C Str] = ClosureTag(Test.8) Test.7;
|
||||||
ret Test.26;
|
ret Test.26;
|
||||||
|
|
||||||
|
procedure Test.6 (Test.21, #Attr.12):
|
||||||
|
let Test.5 : U64 = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
||||||
|
dec #Attr.12;
|
||||||
|
let Test.35 : Str = "";
|
||||||
|
ret Test.35;
|
||||||
|
|
||||||
|
procedure Test.6 (Test.21, #Attr.12):
|
||||||
|
let Test.5 : {} = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||||
|
dec #Attr.12;
|
||||||
|
let Test.23 : Str = "";
|
||||||
|
ret Test.23;
|
||||||
|
|
||||||
procedure Test.8 (Test.27, #Attr.12):
|
procedure Test.8 (Test.27, #Attr.12):
|
||||||
let Test.7 : Str = UnionAtIndex (Id 2) (Index 0) #Attr.12;
|
let Test.7 : Str = UnionAtIndex (Id 2) (Index 0) #Attr.12;
|
||||||
inc Test.7;
|
inc Test.7;
|
||||||
|
@ -38,11 +38,11 @@ procedure Test.0 ():
|
||||||
in
|
in
|
||||||
switch Test.12:
|
switch Test.12:
|
||||||
case 0:
|
case 0:
|
||||||
let Test.14 : Str = CallByName #Multimorphic.0 Test.11 Test.4;
|
let Test.14 : Str = CallByName Test.6 Test.11 Test.4;
|
||||||
jump Test.13 Test.14;
|
jump Test.13 Test.14;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
let Test.15 : Str = CallByName #Multimorphic.1 Test.11 Test.4;
|
let Test.15 : Str = CallByName Test.6 Test.11 Test.4;
|
||||||
jump Test.13 Test.15;
|
jump Test.13 Test.15;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -1530,19 +1530,18 @@ fn tail_call_with_different_layout() {
|
||||||
fn multimorphic_lambda_set_capture() {
|
fn multimorphic_lambda_set_capture() {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
capture : a -> ({} -> Str)
|
capture : _ -> ({} -> Str)
|
||||||
capture = \val ->
|
capture = \val ->
|
||||||
\{} ->
|
\{} ->
|
||||||
when val is
|
Num.toStr val
|
||||||
_ -> ""
|
|
||||||
|
|
||||||
x : [True, False]
|
x : [True, False]
|
||||||
x = True
|
x = True
|
||||||
|
|
||||||
fun =
|
fun =
|
||||||
when x is
|
when x is
|
||||||
True -> capture {}
|
True -> capture 123u64
|
||||||
False -> capture ""
|
False -> capture 18u8
|
||||||
|
|
||||||
fun {}
|
fun {}
|
||||||
"#
|
"#
|
||||||
|
|
|
@ -61,6 +61,7 @@ pub fn jit_to_ast<'a, A: ReplApp<'a>>(
|
||||||
ProcLayout {
|
ProcLayout {
|
||||||
arguments: [],
|
arguments: [],
|
||||||
result,
|
result,
|
||||||
|
..
|
||||||
} => {
|
} => {
|
||||||
// this is a thunk
|
// this is a thunk
|
||||||
jit_to_ast_help(&mut env, app, main_fn_name, &result, content)
|
jit_to_ast_help(&mut env, app, main_fn_name, &result, content)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue