Lift Niche from just captures-niche to generic niche

This commit is contained in:
Ayaz Hafiz 2022-12-27 16:21:17 -06:00
parent ea53a50447
commit 972046445b
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
16 changed files with 119 additions and 140 deletions

View file

@ -15,7 +15,7 @@ use roc_mono::ir::{
Literal, ModifyRc, OptLevel, Proc, ProcLayout, SingleEntryPoint, Stmt, Literal, ModifyRc, OptLevel, Proc, ProcLayout, SingleEntryPoint, Stmt,
}; };
use roc_mono::layout::{ use roc_mono::layout::{
Builtin, CapturesNiche, FieldOrderHash, Layout, RawFunctionLayout, STLayoutInterner, Builtin, CapturesNiche, FieldOrderHash, Layout, Niche, RawFunctionLayout, STLayoutInterner,
UnionLayout, UnionLayout,
}; };
@ -31,7 +31,7 @@ pub fn func_name_bytes(proc: &Proc) -> [u8; SIZE] {
let bytes = func_name_bytes_help( let bytes = func_name_bytes_help(
proc.name.name(), proc.name.name(),
proc.args.iter().map(|x| x.0), proc.args.iter().map(|x| x.0),
proc.name.captures_niche(), proc.name.niche(),
&proc.ret_layout, &proc.ret_layout,
); );
bytes bytes
@ -75,7 +75,7 @@ impl TagUnionId {
pub fn func_name_bytes_help<'a, I>( pub fn func_name_bytes_help<'a, I>(
symbol: Symbol, symbol: Symbol,
argument_layouts: I, argument_layouts: I,
captures_niche: CapturesNiche<'a>, niche: Niche<'a>,
return_layout: &Layout<'a>, return_layout: &Layout<'a>,
) -> [u8; SIZE] ) -> [u8; SIZE]
where where
@ -94,7 +94,7 @@ where
layout.hash(&mut hasher); layout.hash(&mut hasher);
} }
captures_niche.hash(&mut hasher); niche.hash(&mut hasher);
return_layout.hash(&mut hasher); return_layout.hash(&mut hasher);
@ -189,22 +189,14 @@ 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( let bytes =
*symbol, func_name_bytes_help(*symbol, it, Niche::NONE, &top_level.result);
it,
CapturesNiche::no_niche(),
&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 = func_name_bytes_help( let bytes =
*symbol, func_name_bytes_help(*symbol, [], Niche::NONE, &top_level.result);
[],
CapturesNiche::no_niche(),
&top_level.result,
);
host_exposed_functions.push((bytes, top_level.arguments)); host_exposed_functions.push((bytes, top_level.arguments));
} }
@ -237,7 +229,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(),
CapturesNiche::no_niche(), Niche::NONE,
&entry_point_layout.result, &entry_point_layout.result,
); );
let roc_main = FuncName(&roc_main_bytes); let roc_main = FuncName(&roc_main_bytes);
@ -265,19 +257,14 @@ where
field_order_hash: FieldOrderHash::from_ordered_fields(&[]), field_order_hash: FieldOrderHash::from_ordered_fields(&[]),
field_layouts: &[], field_layouts: &[],
}, },
captures_niche: CapturesNiche::no_niche(), niche: Niche::NONE,
}; };
let host_exposed: Vec<_> = symbols let host_exposed: Vec<_> = symbols
.iter() .iter()
.map(|symbol| { .map(|symbol| {
( (
func_name_bytes_help( func_name_bytes_help(*symbol, [], Niche::NONE, &layout.result),
*symbol,
[],
CapturesNiche::no_niche(),
&layout.result,
),
[].as_slice(), [].as_slice(),
) )
}) })
@ -808,7 +795,7 @@ fn call_spec<'a>(
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 args_it = arg_layouts.iter().copied(); let args_it = arg_layouts.iter().copied();
let captures_niche = name.captures_niche(); let captures_niche = name.niche();
let bytes = func_name_bytes_help(name.name(), args_it, captures_niche, ret_layout); let bytes = func_name_bytes_help(name.name(), args_it, captures_niche, ret_layout);
let name = FuncName(&bytes); let name = FuncName(&bytes);
let module = MOD_APP; let module = MOD_APP;
@ -860,7 +847,7 @@ fn call_spec<'a>(
let update_mode_var = UpdateModeVar(&mode); let update_mode_var = UpdateModeVar(&mode);
let args_it = passed_function.argument_layouts.iter().copied(); let args_it = passed_function.argument_layouts.iter().copied();
let captures_niche = passed_function.name.captures_niche(); let captures_niche = passed_function.name.niche();
let bytes = func_name_bytes_help( let bytes = func_name_bytes_help(
passed_function.name.name(), passed_function.name.name(),
args_it, args_it,

View file

@ -45,8 +45,8 @@ use roc_mono::ir::{
OptLevel, ProcLayout, SingleEntryPoint, OptLevel, ProcLayout, SingleEntryPoint,
}; };
use roc_mono::layout::{ use roc_mono::layout::{
Builtin, CapturesNiche, LambdaName, LambdaSet, Layout, LayoutIds, RawFunctionLayout, Builtin, LambdaName, LambdaSet, Layout, LayoutIds, Niche, RawFunctionLayout, STLayoutInterner,
STLayoutInterner, TagIdIntType, UnionLayout, TagIdIntType, UnionLayout,
}; };
use roc_std::RocDec; use roc_std::RocDec;
use roc_target::{PtrWidth, TargetInfo}; use roc_target::{PtrWidth, TargetInfo};
@ -620,12 +620,8 @@ 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( let bytes =
symbol, roc_alias_analysis::func_name_bytes_help(symbol, it, Niche::NONE, &top_level.result);
it,
CapturesNiche::no_niche(),
&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();
@ -637,14 +633,8 @@ 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( let roc_main_fn =
env, function_value_by_func_spec(env, *func_spec, symbol, &[], Niche::NONE, &Layout::UNIT);
*func_spec,
symbol,
&[],
CapturesNiche::no_niche(),
&Layout::UNIT,
);
let main_fn_name = "$Test.main"; let main_fn_name = "$Test.main";
@ -681,12 +671,8 @@ fn promote_to_wasm_test_wrapper<'a, 'ctx, 'env>(
let main_fn_name = "test_wrapper"; let main_fn_name = "test_wrapper";
let it = top_level.arguments.iter().copied(); let it = top_level.arguments.iter().copied();
let bytes = roc_alias_analysis::func_name_bytes_help( let bytes =
symbol, roc_alias_analysis::func_name_bytes_help(symbol, it, Niche::NONE, &top_level.result);
it,
CapturesNiche::no_niche(),
&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();
@ -698,14 +684,8 @@ fn promote_to_wasm_test_wrapper<'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( let roc_main_fn =
env, function_value_by_func_spec(env, *func_spec, symbol, &[], Niche::NONE, &Layout::UNIT);
*func_spec,
symbol,
&[],
CapturesNiche::no_niche(),
&Layout::UNIT,
);
let output_type = match roc_main_fn.get_type().get_return_type() { let output_type = match roc_main_fn.get_type().get_return_type() {
Some(return_type) => { Some(return_type) => {
@ -3546,7 +3526,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: CapturesNiche<'a>, niche: Niche<'a>,
return_layout: Layout<'a>, return_layout: Layout<'a>,
layout_ids: &mut LayoutIds<'a>, layout_ids: &mut LayoutIds<'a>,
) { ) {
@ -3555,7 +3535,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, niche,
}; };
let c_function_name: String = layout_ids let c_function_name: String = layout_ids
@ -4676,12 +4656,12 @@ pub fn build_procedures_expose_expects<'a, 'ctx, 'env>(
Some(&std::env::temp_dir().join("test.ll")), Some(&std::env::temp_dir().join("test.ll")),
); );
let captures_niche = CapturesNiche::no_niche(); let captures_niche = Niche::NONE;
let top_level = ProcLayout { let top_level = ProcLayout {
arguments: &[], arguments: &[],
result: Layout::UNIT, result: Layout::UNIT,
captures_niche, niche: captures_niche,
}; };
let mut expect_names = Vec::with_capacity_in(expects.len(), env.arena); let mut expect_names = Vec::with_capacity_in(expects.len(), env.arena);
@ -4904,7 +4884,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.name.niche(),
proc.ret_layout, proc.ret_layout,
layout_ids, layout_ids,
); );
@ -4951,7 +4931,7 @@ fn expose_alias_to_host<'a, 'ctx, 'env>(
let bytes = roc_alias_analysis::func_name_bytes_help( let bytes = roc_alias_analysis::func_name_bytes_help(
exposed_function_symbol, exposed_function_symbol,
it, it,
CapturesNiche::no_niche(), Niche::NONE,
&top_level.result, &top_level.result,
); );
let func_name = FuncName(&bytes); let func_name = FuncName(&bytes);
@ -4970,7 +4950,7 @@ fn expose_alias_to_host<'a, 'ctx, 'env>(
*func_spec, *func_spec,
exposed_function_symbol, exposed_function_symbol,
top_level.arguments, top_level.arguments,
CapturesNiche::no_niche(), Niche::NONE,
&top_level.result, &top_level.result,
) )
} }
@ -5305,19 +5285,19 @@ pub(crate) 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: CapturesNiche<'a>, niche: Niche<'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, captures_niche, result, symbol, fn_name) function_value_by_name_help(env, arguments, 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: CapturesNiche<'a>, _niche: Niche<'a>,
result: &Layout<'a>, result: &Layout<'a>,
symbol: Symbol, symbol: Symbol,
fn_name: &str, fn_name: &str,
@ -5368,7 +5348,7 @@ fn roc_call_with_args<'a, 'ctx, 'env>(
func_spec, func_spec,
name.name(), name.name(),
argument_layouts, argument_layouts,
name.captures_niche(), name.niche(),
result_layout, result_layout,
); );

View file

@ -2308,7 +2308,7 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
func_spec, func_spec,
function_name.name(), function_name.name(),
argument_layouts, argument_layouts,
function_name.captures_niche(), function_name.niche(),
return_layout, return_layout,
); );

View file

@ -1249,7 +1249,7 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
let proc_layout = ProcLayout { let proc_layout = ProcLayout {
arguments: arg_layouts, arguments: arg_layouts,
result: **result, result: **result,
captures_niche: func_sym.captures_niche(), niche: func_sym.niche(),
}; };
self.expr_call_by_name( self.expr_call_by_name(
func_sym.name(), func_sym.name(),

View file

@ -2205,7 +2205,7 @@ 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(), niche: fn_name.niche(),
}; };
let passed_proc_index = backend let passed_proc_index = backend
.proc_lookup .proc_lookup
@ -2249,13 +2249,13 @@ 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: fn_name.captures_niche(), niche: fn_name.niche(),
} }
} }
ProcSource::HigherOrderCompare(_) => ProcLayout { ProcSource::HigherOrderCompare(_) => ProcLayout {
arguments: wrapper_arg_layouts.into_bump_slice(), arguments: wrapper_arg_layouts.into_bump_slice(),
result: *result_layout, result: *result_layout,
captures_niche: fn_name.captures_niche(), niche: fn_name.niche(),
}, },
ProcSource::Roc | ProcSource::Helper => { ProcSource::Roc | ProcSource::Helper => {
internal_error!("Should never reach here for {:?}", helper_proc_source) internal_error!("Should never reach here for {:?}", helper_proc_source)

View file

@ -36,7 +36,7 @@ use roc_mono::ir::{
UpdateModeIds, UpdateModeIds,
}; };
use roc_mono::layout::{ use roc_mono::layout::{
CapturesNiche, LambdaName, Layout, LayoutCache, LayoutProblem, STLayoutInterner, CapturesNiche, LambdaName, Layout, LayoutCache, LayoutProblem, Niche, STLayoutInterner,
}; };
use roc_packaging::cache::{self, RocCacheDir}; use roc_packaging::cache::{self, RocCacheDir};
#[cfg(not(target_family = "wasm"))] #[cfg(not(target_family = "wasm"))]
@ -3426,7 +3426,7 @@ fn proc_layout_for<'a>(
roc_mono::ir::ProcLayout { roc_mono::ir::ProcLayout {
arguments: &[], arguments: &[],
result: Layout::struct_no_name_order(&[]), result: Layout::struct_no_name_order(&[]),
captures_niche: CapturesNiche::no_niche(), niche: Niche::NONE,
} }
} }
} }

View file

@ -513,7 +513,7 @@ impl<'a> BorrowInfState<'a> {
.. ..
} => { } => {
let top_level = let top_level =
ProcLayout::new(self.arena, arg_layouts, name.captures_niche(), **ret_layout); ProcLayout::new(self.arena, arg_layouts, name.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
@ -556,7 +556,7 @@ 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(), niche: passed_function.name.niche(),
}; };
let function_ps = let function_ps =
@ -739,8 +739,7 @@ impl<'a> BorrowInfState<'a> {
Stmt::Ret(z), Stmt::Ret(z),
) = (v, b) ) = (v, b)
{ {
let top_level = let top_level = ProcLayout::new(self.arena, arg_layouts, g.niche(), **ret_layout);
ProcLayout::new(self.arena, arg_layouts, g.captures_niche(), **ret_layout);
if self.current_proc == g.name() && 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)

View file

@ -9,7 +9,9 @@ use crate::ir::{
Call, CallSpecId, CallType, Expr, HostExposedLayouts, JoinPointId, ModifyRc, Proc, ProcLayout, Call, CallSpecId, CallType, Expr, HostExposedLayouts, JoinPointId, ModifyRc, Proc, ProcLayout,
SelfRecursive, Stmt, UpdateModeId, SelfRecursive, Stmt, UpdateModeId,
}; };
use crate::layout::{Builtin, CapturesNiche, LambdaName, Layout, STLayoutInterner, UnionLayout}; use crate::layout::{
Builtin, CapturesNiche, LambdaName, Layout, Niche, STLayoutInterner, UnionLayout,
};
mod equality; mod equality;
mod refcount; mod refcount;
@ -404,23 +406,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: CapturesNiche::no_niche(), niche: Niche::NONE,
}, },
HelperOp::Dec => ProcLayout { HelperOp::Dec => ProcLayout {
arguments: self.arena.alloc([*layout]), arguments: self.arena.alloc([*layout]),
result: LAYOUT_UNIT, result: LAYOUT_UNIT,
captures_niche: CapturesNiche::no_niche(), niche: Niche::NONE,
}, },
HelperOp::Reset => ProcLayout { HelperOp::Reset => ProcLayout {
arguments: self.arena.alloc([*layout]), arguments: self.arena.alloc([*layout]),
result: *layout, result: *layout,
captures_niche: CapturesNiche::no_niche(), niche: Niche::NONE,
}, },
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: CapturesNiche::no_niche(), niche: Niche::NONE,
}, },
}; };

View file

@ -556,7 +556,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
let proc_layout = ProcLayout { let proc_layout = ProcLayout {
arguments: arg_layouts, arguments: arg_layouts,
result: **ret_layout, result: **ret_layout,
captures_niche: name.captures_niche(), niche: name.niche(),
}; };
if !self.procs.contains_key(&(name.name(), proc_layout)) { if !self.procs.contains_key(&(name.name(), proc_layout)) {
let similar = self let similar = self

View file

@ -6,7 +6,7 @@ use ven_pretty::{Arena, DocAllocator, DocBuilder};
use crate::{ use crate::{
ir::{Parens, ProcLayout}, ir::{Parens, ProcLayout},
layout::{CapturesNiche, Layout}, layout::{Layout, Niche},
}; };
use super::{ use super::{
@ -465,7 +465,7 @@ where
let ProcLayout { let ProcLayout {
arguments, arguments,
result, result,
captures_niche, niche: captures_niche,
} = proc_layout; } = proc_layout;
let args = f.intersperse( let args = f.intersperse(
arguments arguments
@ -478,20 +478,19 @@ where
f.reflow(" -> "), f.reflow(" -> "),
result.to_doc(f, interner, Parens::NotNeeded), result.to_doc(f, interner, Parens::NotNeeded),
]); ]);
let niche = if captures_niche == CapturesNiche::no_niche() { let niche = match captures_niche {
f.reflow("(no niche)") Niche::NONE => f.reflow("(no niche)"),
} else { Niche::Captures(captures_niche) => f.concat([
f.concat([
f.reflow("(niche {"), f.reflow("(niche {"),
f.intersperse( f.intersperse(
captures_niche captures_niche
.0 .captures()
.iter() .iter()
.map(|&c| interner.get(c).to_doc(f, interner, Parens::NotNeeded)), .map(|&c| interner.get(c).to_doc(f, interner, Parens::NotNeeded)),
f.reflow(", "), f.reflow(", "),
), ),
f.reflow("})"), f.reflow("})"),
]) ]),
}; };
f.concat([fun, f.space(), niche]) f.concat([fun, f.space(), niche])
} }

View file

@ -595,7 +595,7 @@ impl<'a, 'i> Context<'a, 'i> {
.. ..
} => { } => {
let top_level = let top_level =
ProcLayout::new(self.arena, arg_layouts, name.captures_niche(), **ret_layout); ProcLayout::new(self.arena, arg_layouts, name.niche(), **ret_layout);
// get the borrow signature // get the borrow signature
let ps = self let ps = self
@ -645,7 +645,7 @@ impl<'a, 'i> Context<'a, 'i> {
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(), niche: passed_function.name.niche(),
}; };
let function_ps = match self let function_ps = match self

View file

@ -1,9 +1,9 @@
#![allow(clippy::manual_map)] #![allow(clippy::manual_map)]
use crate::layout::{ use crate::layout::{
self, Builtin, CapturesNiche, ClosureCallOptions, ClosureRepresentation, EnumDispatch, self, Builtin, ClosureCallOptions, ClosureRepresentation, EnumDispatch, LambdaName, LambdaSet,
LambdaName, LambdaSet, Layout, LayoutCache, LayoutProblem, RawFunctionLayout, STLayoutInterner, Layout, LayoutCache, LayoutProblem, Niche, RawFunctionLayout, STLayoutInterner, TagIdIntType,
TagIdIntType, UnionLayout, WrappedVariant, UnionLayout, WrappedVariant,
}; };
use bumpalo::collections::{CollectIn, Vec}; use bumpalo::collections::{CollectIn, Vec};
use bumpalo::Bump; use bumpalo::Bump;
@ -3391,7 +3391,7 @@ fn specialize_proc_help<'a>(
let top_level = ProcLayout::new( let top_level = ProcLayout::new(
env.arena, env.arena,
top_level_arguments.into_bump_slice(), top_level_arguments.into_bump_slice(),
CapturesNiche::no_niche(), Niche::NONE,
*return_layout, *return_layout,
); );
@ -3424,7 +3424,7 @@ fn specialize_proc_help<'a>(
*symbol, *symbol,
( (
name, name,
ProcLayout::new(env.arena, &[], CapturesNiche::no_niche(), result), ProcLayout::new(env.arena, &[], Niche::NONE, result),
layout, layout,
), ),
); );
@ -3956,14 +3956,14 @@ fn specialize_variable<'a>(
pub struct ProcLayout<'a> { pub struct ProcLayout<'a> {
pub arguments: &'a [Layout<'a>], pub arguments: &'a [Layout<'a>],
pub result: Layout<'a>, pub result: Layout<'a>,
pub captures_niche: CapturesNiche<'a>, pub niche: Niche<'a>,
} }
impl<'a> ProcLayout<'a> { impl<'a> ProcLayout<'a> {
pub(crate) fn new( pub(crate) fn new(
arena: &'a Bump, arena: &'a Bump,
old_arguments: &'a [Layout<'a>], old_arguments: &'a [Layout<'a>],
old_captures_niche: CapturesNiche<'a>, old_niche: Niche<'a>,
result: Layout<'a>, result: Layout<'a>,
) -> Self { ) -> Self {
let mut arguments = Vec::with_capacity_in(old_arguments.len(), arena); let mut arguments = Vec::with_capacity_in(old_arguments.len(), arena);
@ -3978,7 +3978,7 @@ impl<'a> ProcLayout<'a> {
ProcLayout { ProcLayout {
arguments: arguments.into_bump_slice(), arguments: arguments.into_bump_slice(),
captures_niche: old_captures_niche, niche: old_niche,
result: new_result, result: new_result,
} }
} }
@ -3992,10 +3992,10 @@ impl<'a> ProcLayout<'a> {
RawFunctionLayout::Function(arguments, lambda_set, result) => { RawFunctionLayout::Function(arguments, lambda_set, result) => {
let arguments = let arguments =
lambda_set.extend_argument_list_for_named(arena, lambda_name, arguments); lambda_set.extend_argument_list_for_named(arena, lambda_name, arguments);
ProcLayout::new(arena, arguments, lambda_name.captures_niche(), *result) ProcLayout::new(arena, arguments, lambda_name.niche(), *result)
} }
RawFunctionLayout::ZeroArgumentThunk(result) => { RawFunctionLayout::ZeroArgumentThunk(result) => {
ProcLayout::new(arena, &[], CapturesNiche::no_niche(), result) ProcLayout::new(arena, &[], Niche::NONE, result)
} }
} }
} }
@ -8382,8 +8382,7 @@ fn specialize_symbol<'a>(
// let layout = Layout::Closure(argument_layouts, lambda_set, ret_layout); // let layout = Layout::Closure(argument_layouts, lambda_set, ret_layout);
// panic!("suspicious"); // panic!("suspicious");
let layout = Layout::LambdaSet(lambda_set); let layout = Layout::LambdaSet(lambda_set);
let top_level = let top_level = ProcLayout::new(env.arena, &[], Niche::NONE, layout);
ProcLayout::new(env.arena, &[], CapturesNiche::no_niche(), layout);
procs.insert_passed_by_name( procs.insert_passed_by_name(
env, env,
arg_var, arg_var,
@ -8427,8 +8426,7 @@ fn specialize_symbol<'a>(
} }
RawFunctionLayout::ZeroArgumentThunk(ret_layout) => { RawFunctionLayout::ZeroArgumentThunk(ret_layout) => {
// this is a 0-argument thunk // this is a 0-argument thunk
let top_level = let top_level = ProcLayout::new(env.arena, &[], Niche::NONE, ret_layout);
ProcLayout::new(env.arena, &[], CapturesNiche::no_niche(), ret_layout);
procs.insert_passed_by_name( procs.insert_passed_by_name(
env, env,
arg_var, arg_var,
@ -8756,12 +8754,7 @@ fn call_by_name_help<'a>(
let top_level_layout = { let top_level_layout = {
let argument_layouts = let argument_layouts =
lambda_set.extend_argument_list_for_named(env.arena, proc_name, argument_layouts); lambda_set.extend_argument_list_for_named(env.arena, proc_name, argument_layouts);
ProcLayout::new( ProcLayout::new(env.arena, argument_layouts, proc_name.niche(), *ret_layout)
env.arena,
argument_layouts,
proc_name.captures_niche(),
*ret_layout,
)
}; };
// the variables of the given arguments // the variables of the given arguments
@ -9016,7 +9009,7 @@ fn call_by_name_module_thunk<'a>(
assigned: Symbol, assigned: Symbol,
hole: &'a Stmt<'a>, hole: &'a Stmt<'a>,
) -> Stmt<'a> { ) -> Stmt<'a> {
let top_level_layout = ProcLayout::new(env.arena, &[], CapturesNiche::no_niche(), *ret_layout); let top_level_layout = ProcLayout::new(env.arena, &[], Niche::NONE, *ret_layout);
let inner_layout = *ret_layout; let inner_layout = *ret_layout;

View file

@ -1241,18 +1241,28 @@ impl std::fmt::Debug for LambdaSet<'_> {
/// ///
/// See also https://github.com/roc-lang/roc/issues/3336. /// See also https://github.com/roc-lang/roc/issues/3336.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct CapturesNiche<'a>(pub(crate) &'a [InLayout<'a>]); pub struct CapturesNiche<'a>(&'a [InLayout<'a>]);
impl CapturesNiche<'_> { impl<'a> CapturesNiche<'a> {
pub fn no_niche() -> Self { pub(crate) fn captures(&self) -> &'a [Layout<'a>] {
Self(&[]) self.0
} }
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Niche<'a> {
/// A niche for a proc are its captures.
Captures(CapturesNiche<'a>),
}
impl<'a> Niche<'a> {
pub const NONE: Niche<'a> = Niche::Captures(CapturesNiche(&[]));
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct LambdaName<'a> { pub struct LambdaName<'a> {
name: Symbol, name: Symbol,
captures_niche: CapturesNiche<'a>, niche: Niche<'a>,
} }
impl<'a> LambdaName<'a> { impl<'a> LambdaName<'a> {
@ -1262,29 +1272,29 @@ impl<'a> LambdaName<'a> {
} }
#[inline(always)] #[inline(always)]
pub fn captures_niche(&self) -> CapturesNiche<'a> { pub fn niche(&self) -> Niche<'a> {
self.captures_niche self.niche
} }
#[inline(always)] #[inline(always)]
pub fn no_captures(&self) -> bool { pub(crate) fn no_captures(&self) -> bool {
self.captures_niche.0.is_empty() match self.niche {
Niche::NONE => true,
Niche::Captures(captures) => captures.0.is_empty(),
}
} }
#[inline(always)] #[inline(always)]
pub fn no_niche(name: Symbol) -> Self { pub fn no_niche(name: Symbol) -> Self {
Self { Self {
name, name,
captures_niche: CapturesNiche::no_niche(), niche: Niche::NONE,
} }
} }
#[inline(always)] #[inline(always)]
pub fn replace_name(&self, name: Symbol) -> Self { pub(crate) fn replace_name(&self, name: Symbol) -> Self {
Self { Self { name, ..*self }
name,
captures_niche: self.captures_niche,
}
} }
} }
@ -1377,9 +1387,12 @@ impl<'a> LambdaSet<'a> {
} }
pub fn iter_set(&self) -> impl ExactSizeIterator<Item = LambdaName<'a>> { pub fn iter_set(&self) -> impl ExactSizeIterator<Item = LambdaName<'a>> {
self.set.iter().map(|(name, captures_layouts)| LambdaName { self.set.iter().map(|(name, captures_layouts)| {
name: *name, let niche = match captures_layouts {
captures_niche: CapturesNiche(captures_layouts), [] => Niche::NONE,
_ => Niche::Captures(CapturesNiche(captures_layouts)),
};
LambdaName { name: *name, niche }
}) })
} }
@ -1403,12 +1416,17 @@ impl<'a> LambdaSet<'a> {
{ {
debug_assert!(self.contains(lambda_name.name)); debug_assert!(self.contains(lambda_name.name));
let captures = match lambda_name.niche {
Niche::Captures(captures) => captures.0,
Niche::NONE => &[],
};
let comparator = |other_name: Symbol, other_captures_layouts: &[InLayout]| { let comparator = |other_name: Symbol, other_captures_layouts: &[InLayout]| {
other_name == lambda_name.name other_name == lambda_name.name
// Make sure all captures are equal // Make sure all captures are equal
&& other_captures_layouts && other_captures_layouts
.iter() .iter()
.eq(lambda_name.captures_niche.0) .eq(captures)
}; };
self.layout_for_member(interner, comparator) self.layout_for_member(interner, comparator)
@ -1455,7 +1473,7 @@ impl<'a> LambdaSet<'a> {
LambdaName { LambdaName {
name: *name, name: *name,
captures_niche: CapturesNiche(layouts), niche: Niche::Captures(CapturesNiche(layouts)),
} }
} }
@ -1658,6 +1676,7 @@ impl<'a> LambdaSet<'a> {
lambda_name: LambdaName<'a>, lambda_name: LambdaName<'a>,
argument_layouts: &'a [Layout<'a>], argument_layouts: &'a [Layout<'a>],
) -> &'a [Layout<'a>] { ) -> &'a [Layout<'a>] {
let Niche::Captures(CapturesNiche(captures)) = lambda_name.niche;
// TODO(https://github.com/roc-lang/roc/issues/4831): we should turn on this debug-assert; // TODO(https://github.com/roc-lang/roc/issues/4831): we should turn on this debug-assert;
// however, currently it causes false-positives, because host-exposed functions that are // however, currently it causes false-positives, because host-exposed functions that are
// function pointers to platform-exposed functions are compiled as if they are proper // function pointers to platform-exposed functions are compiled as if they are proper
@ -1674,7 +1693,7 @@ impl<'a> LambdaSet<'a> {
// ); // );
// If we don't capture, there is nothing to extend. // If we don't capture, there is nothing to extend.
if lambda_name.captures_niche.0.is_empty() { if captures.is_empty() {
argument_layouts argument_layouts
} else { } else {
let mut arguments = Vec::with_capacity_in(argument_layouts.len() + 1, arena); let mut arguments = Vec::with_capacity_in(argument_layouts.len() + 1, arena);

View file

@ -124,7 +124,7 @@ fn build_app_mono<'a>(
let proc_layout = ProcLayout { let proc_layout = ProcLayout {
arguments: &[], arguments: &[],
result: int_layout, result: int_layout,
captures_niche: CapturesNiche::no_niche(), niche: CapturesNiche::no_niche(),
}; };
let mut app = MutMap::default(); let mut app = MutMap::default();

View file

@ -62,7 +62,7 @@ pub fn jit_to_ast<'a, A: ReplApp<'a>>(
ProcLayout { ProcLayout {
arguments: [], arguments: [],
result, result,
captures_niche: _, niche: _,
} => { } => {
// This is a thunk, which cannot be defined in userspace, so we know // This is a thunk, which cannot be defined in userspace, so we know
// it's `main` and can be executed. // it's `main` and can be executed.

View file

@ -5,7 +5,7 @@ use {
roc_module::symbol::Interns, roc_module::symbol::Interns,
roc_mono::{ roc_mono::{
ir::ProcLayout, ir::ProcLayout,
layout::{CapturesNiche, Layout, LayoutCache}, layout::{Layout, LayoutCache, Niche},
}, },
roc_parse::ast::Expr, roc_parse::ast::Expr,
roc_repl_eval::{eval::jit_to_ast, ReplAppMemory}, roc_repl_eval::{eval::jit_to_ast, ReplAppMemory},
@ -67,7 +67,7 @@ pub fn get_values<'a>(
let proc_layout = ProcLayout { let proc_layout = ProcLayout {
arguments: &[], arguments: &[],
result: layout, result: layout,
captures_niche: CapturesNiche::no_niche(), niche: Niche::NONE,
}; };
jit_to_ast( jit_to_ast(