mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 23:04:49 +00:00
commit
449ec19b0f
12 changed files with 209 additions and 192 deletions
|
@ -445,7 +445,6 @@ fn call_spec(
|
|||
match &call.call_type {
|
||||
ByName {
|
||||
name: symbol,
|
||||
full_layout: _,
|
||||
ret_layout,
|
||||
arg_layouts,
|
||||
specialization_id,
|
||||
|
|
|
@ -24,9 +24,8 @@ pub fn infer_borrow<'a>(
|
|||
items: MutMap::default(),
|
||||
};
|
||||
|
||||
for ((s, top_level), proc) in procs {
|
||||
let key = (*s, arena.alloc(*top_level).full());
|
||||
param_map.visit_proc(arena, proc, key);
|
||||
for (key, proc) in procs {
|
||||
param_map.visit_proc(arena, proc, *key);
|
||||
}
|
||||
|
||||
let mut env = BorrowInfState {
|
||||
|
@ -51,8 +50,7 @@ pub fn infer_borrow<'a>(
|
|||
// mutually recursive functions (or just make all their arguments owned)
|
||||
|
||||
for (key, proc) in procs {
|
||||
let layout = arena.alloc(key.1).full();
|
||||
env.collect_proc(proc, layout);
|
||||
env.collect_proc(proc, key.1);
|
||||
}
|
||||
|
||||
if !env.modified {
|
||||
|
@ -69,7 +67,7 @@ pub fn infer_borrow<'a>(
|
|||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
||||
pub enum Key<'a> {
|
||||
Declaration(Symbol, Layout<'a>),
|
||||
Declaration(Symbol, TopLevelFunctionLayout<'a>),
|
||||
JoinPoint(JoinPointId),
|
||||
}
|
||||
|
||||
|
@ -98,7 +96,11 @@ impl<'a> IntoIterator for &'a ParamMap<'a> {
|
|||
}
|
||||
|
||||
impl<'a> ParamMap<'a> {
|
||||
pub fn get_symbol(&self, symbol: Symbol, layout: Layout<'a>) -> Option<&'a [Param<'a>]> {
|
||||
pub fn get_symbol(
|
||||
&self,
|
||||
symbol: Symbol,
|
||||
layout: TopLevelFunctionLayout<'a>,
|
||||
) -> Option<&'a [Param<'a>]> {
|
||||
let key = Key::Declaration(symbol, layout);
|
||||
|
||||
self.items.get(&key).copied()
|
||||
|
@ -153,7 +155,12 @@ impl<'a> ParamMap<'a> {
|
|||
.into_bump_slice()
|
||||
}
|
||||
|
||||
fn visit_proc(&mut self, arena: &'a Bump, proc: &Proc<'a>, key: (Symbol, Layout<'a>)) {
|
||||
fn visit_proc(
|
||||
&mut self,
|
||||
arena: &'a Bump,
|
||||
proc: &Proc<'a>,
|
||||
key: (Symbol, TopLevelFunctionLayout<'a>),
|
||||
) {
|
||||
if proc.must_own_arguments {
|
||||
self.visit_proc_always_owned(arena, proc, key);
|
||||
return;
|
||||
|
@ -171,7 +178,7 @@ impl<'a> ParamMap<'a> {
|
|||
&mut self,
|
||||
arena: &'a Bump,
|
||||
proc: &Proc<'a>,
|
||||
key: (Symbol, Layout<'a>),
|
||||
key: (Symbol, TopLevelFunctionLayout<'a>),
|
||||
) {
|
||||
let already_in_there = self.items.insert(
|
||||
Key::Declaration(proc.name, key.1),
|
||||
|
@ -359,12 +366,17 @@ impl<'a> BorrowInfState<'a> {
|
|||
|
||||
match call_type {
|
||||
ByName {
|
||||
name, full_layout, ..
|
||||
name,
|
||||
ret_layout,
|
||||
arg_layouts,
|
||||
..
|
||||
} => {
|
||||
let top_level = TopLevelFunctionLayout::new(self.arena, arg_layouts, *ret_layout);
|
||||
|
||||
// get the borrow signature of the applied function
|
||||
let ps = self
|
||||
.param_map
|
||||
.get_symbol(*name, *full_layout)
|
||||
.get_symbol(*name, top_level)
|
||||
.expect("function is defined");
|
||||
|
||||
// the return value will be owned
|
||||
|
@ -402,7 +414,10 @@ impl<'a> BorrowInfState<'a> {
|
|||
|
||||
debug_assert!(op.is_higher_order());
|
||||
|
||||
let closure_layout = Layout::FunctionPointer(arg_layouts, ret_layout);
|
||||
let closure_layout = TopLevelFunctionLayout {
|
||||
arguments: arg_layouts,
|
||||
result: *ret_layout,
|
||||
};
|
||||
|
||||
match op {
|
||||
ListMap | ListKeepIf | ListKeepOks | ListKeepErrs => {
|
||||
|
@ -584,7 +599,8 @@ impl<'a> BorrowInfState<'a> {
|
|||
call_type:
|
||||
crate::ir::CallType::ByName {
|
||||
name: g,
|
||||
full_layout,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
..
|
||||
},
|
||||
arguments: ys,
|
||||
|
@ -593,10 +609,12 @@ impl<'a> BorrowInfState<'a> {
|
|||
Stmt::Ret(z),
|
||||
) = (v, b)
|
||||
{
|
||||
let top_level = TopLevelFunctionLayout::new(self.arena, arg_layouts, *ret_layout);
|
||||
|
||||
if self.current_proc == *g && x == *z {
|
||||
// anonymous functions (for which the ps may not be known)
|
||||
// can never be tail-recursive, so this is fine
|
||||
if let Some(ps) = self.param_map.get_symbol(*g, *full_layout) {
|
||||
if let Some(ps) = self.param_map.get_symbol(*g, top_level) {
|
||||
self.own_params_using_args(ys, ps)
|
||||
}
|
||||
}
|
||||
|
@ -684,7 +702,7 @@ impl<'a> BorrowInfState<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn collect_proc(&mut self, proc: &Proc<'a>, layout: Layout<'a>) {
|
||||
fn collect_proc(&mut self, proc: &Proc<'a>, layout: TopLevelFunctionLayout<'a>) {
|
||||
let old = self.param_set.clone();
|
||||
|
||||
let ys = Vec::from_iter_in(proc.args.iter().map(|t| t.1), self.arena).into_bump_slice();
|
||||
|
|
|
@ -245,9 +245,6 @@ fn layout_for_constructor<'a>(
|
|||
HasFields(fields)
|
||||
}
|
||||
Closure(_arguments, _lambda_set, _result) => {
|
||||
// TODO can this be improved again?
|
||||
// let fpointer = Layout::FunctionPointer(arguments, result);
|
||||
// let fields = arena.alloc([fpointer, *lambda_set.layout]);
|
||||
// HasFields(fields)
|
||||
ConstructorLayout::Unknown
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::borrow::{ParamMap, BORROWED, OWNED};
|
||||
use crate::ir::{Expr, JoinPointId, ModifyRc, Param, Proc, Stmt};
|
||||
use crate::ir::{Expr, JoinPointId, ModifyRc, Param, Proc, Stmt, TopLevelFunctionLayout};
|
||||
use crate::layout::Layout;
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
|
@ -497,7 +497,10 @@ impl<'a> Context<'a> {
|
|||
const FUNCTION: bool = BORROWED;
|
||||
const CLOSURE_DATA: bool = BORROWED;
|
||||
|
||||
let function_layout = Layout::FunctionPointer(arg_layouts, ret_layout);
|
||||
let function_layout = TopLevelFunctionLayout {
|
||||
arguments: arg_layouts,
|
||||
result: *ret_layout,
|
||||
};
|
||||
|
||||
match op {
|
||||
roc_module::low_level::LowLevel::ListMap
|
||||
|
@ -679,12 +682,17 @@ impl<'a> Context<'a> {
|
|||
}
|
||||
|
||||
ByName {
|
||||
name, full_layout, ..
|
||||
name,
|
||||
ret_layout,
|
||||
arg_layouts,
|
||||
..
|
||||
} => {
|
||||
let top_level = TopLevelFunctionLayout::new(self.arena, arg_layouts, *ret_layout);
|
||||
|
||||
// get the borrow signature
|
||||
let ps = self
|
||||
.param_map
|
||||
.get_symbol(*name, *full_layout)
|
||||
.get_symbol(*name, top_level)
|
||||
.expect("function is defined");
|
||||
|
||||
let v = Expr::Call(crate::ir::Call {
|
||||
|
@ -963,12 +971,18 @@ impl<'a> Context<'a> {
|
|||
}
|
||||
|
||||
CallType::ByName {
|
||||
name, full_layout, ..
|
||||
name,
|
||||
ret_layout,
|
||||
arg_layouts,
|
||||
..
|
||||
} => {
|
||||
let top_level =
|
||||
TopLevelFunctionLayout::new(self.arena, arg_layouts, *ret_layout);
|
||||
|
||||
// get the borrow signature
|
||||
let ps = self
|
||||
.param_map
|
||||
.get_symbol(*name, *full_layout)
|
||||
.get_symbol(*name, top_level)
|
||||
.expect("function is defined");
|
||||
self.add_dec_after_application(call.arguments, ps, cont, &invoke_live_vars)
|
||||
}
|
||||
|
@ -1222,7 +1236,7 @@ pub fn visit_proc<'a>(
|
|||
arena: &'a Bump,
|
||||
param_map: &'a ParamMap<'a>,
|
||||
proc: &mut Proc<'a>,
|
||||
layout: Layout<'a>,
|
||||
layout: TopLevelFunctionLayout<'a>,
|
||||
) {
|
||||
let ctx = Context::new(arena, param_map);
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ impl<'a> Proc<'a> {
|
|||
let borrow_params = arena.alloc(crate::borrow::infer_borrow(arena, procs));
|
||||
|
||||
for (key, proc) in procs.iter_mut() {
|
||||
crate::inc_dec::visit_proc(arena, borrow_params, proc, arena.alloc(key.1).full());
|
||||
crate::inc_dec::visit_proc(arena, borrow_params, proc, key.1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -410,8 +410,7 @@ impl<'a> Procs<'a> {
|
|||
let borrow_params = arena.alloc(crate::borrow::infer_borrow(arena, &result));
|
||||
|
||||
for (key, proc) in result.iter_mut() {
|
||||
let layout = arena.alloc(key.1).full();
|
||||
crate::inc_dec::visit_proc(arena, borrow_params, proc, layout);
|
||||
crate::inc_dec::visit_proc(arena, borrow_params, proc, key.1);
|
||||
}
|
||||
|
||||
result
|
||||
|
@ -454,8 +453,7 @@ impl<'a> Procs<'a> {
|
|||
let borrow_params = arena.alloc(crate::borrow::infer_borrow(arena, &result));
|
||||
|
||||
for (key, proc) in result.iter_mut() {
|
||||
let layout = arena.alloc(key.1).full();
|
||||
crate::inc_dec::visit_proc(arena, borrow_params, proc, layout);
|
||||
crate::inc_dec::visit_proc(arena, borrow_params, proc, key.1);
|
||||
}
|
||||
|
||||
(result, borrow_params)
|
||||
|
@ -1138,7 +1136,6 @@ impl UpdateModeId {
|
|||
pub enum CallType<'a> {
|
||||
ByName {
|
||||
name: Symbol,
|
||||
full_layout: Layout<'a>,
|
||||
ret_layout: Layout<'a>,
|
||||
arg_layouts: &'a [Layout<'a>],
|
||||
specialization_id: CallSpecId,
|
||||
|
@ -2627,10 +2624,6 @@ impl<'a> TopLevelFunctionLayout<'a> {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn full(&'a self) -> Layout<'a> {
|
||||
Layout::FunctionPointer(self.arguments, &self.result)
|
||||
}
|
||||
}
|
||||
|
||||
fn specialize_naked_symbol<'a>(
|
||||
|
@ -3701,7 +3694,7 @@ pub fn with_hole<'a>(
|
|||
} => {
|
||||
let loc_body = *boxed_body;
|
||||
|
||||
match layout_cache.from_var(env.arena, function_type, env.subs) {
|
||||
match layout_cache.raw_from_var(env.arena, function_type, env.subs) {
|
||||
Err(e) => panic!("invalid layout {:?}", e),
|
||||
Ok(Layout::Closure(_argument_layouts, lambda_set, _ret_layout)) => {
|
||||
let mut captured_symbols = Vec::from_iter_in(captured_symbols, env.arena);
|
||||
|
@ -3738,43 +3731,6 @@ pub fn with_hole<'a>(
|
|||
|
||||
construct_closure_data(env, lambda_set, name, symbols, assigned, hole)
|
||||
}
|
||||
Ok(Layout::FunctionPointer(_, _)) => {
|
||||
// CLEANUP
|
||||
unreachable!("closures should never have a function pointer layout");
|
||||
|
||||
// match procs.insert_anonymous(
|
||||
// env,
|
||||
// name,
|
||||
// function_type,
|
||||
// arguments,
|
||||
// loc_body,
|
||||
// CapturedSymbols::None,
|
||||
// return_type,
|
||||
// layout_cache,
|
||||
// ) {
|
||||
// Ok(layout) => {
|
||||
// bg!(name);
|
||||
// // TODO should the let have layout Pointer?
|
||||
// // Stmt::Let(assigned, Expr::Struct(&[]), Layout::Struct(&[]), hole)
|
||||
// if false {
|
||||
// let mut hole = hole.clone();
|
||||
// substitute_in_exprs(env.arena, &mut hole, assigned, name);
|
||||
// hole
|
||||
// } else {
|
||||
// Stmt::Let(
|
||||
// assigned,
|
||||
// call_by_pointer(env, procs, name, layout),
|
||||
// layout,
|
||||
// hole,
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Err(_error) => Stmt::RuntimeError(
|
||||
// "TODO convert anonymous function error to a RuntimeError string",
|
||||
// ),
|
||||
// }
|
||||
}
|
||||
Ok(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -3833,11 +3789,10 @@ pub fn with_hole<'a>(
|
|||
|
||||
let full_layout = return_on_layout_error!(
|
||||
env,
|
||||
layout_cache.from_var(env.arena, fn_var, env.subs)
|
||||
layout_cache.raw_from_var(env.arena, fn_var, env.subs)
|
||||
);
|
||||
|
||||
let arg_layouts = match full_layout {
|
||||
Layout::FunctionPointer(args, _) => args,
|
||||
Layout::Closure(args, _, _) => args,
|
||||
_ => unreachable!("function has layout that is not function pointer"),
|
||||
};
|
||||
|
@ -3905,38 +3860,6 @@ pub fn with_hole<'a>(
|
|||
env.arena.alloc(result),
|
||||
);
|
||||
}
|
||||
Layout::FunctionPointer(_, _) => {
|
||||
// CLEANUP
|
||||
unreachable!("should not be a function pointer");
|
||||
|
||||
// let function_symbol = env.unique_symbol();
|
||||
// let closure_data_symbol = function_symbol;
|
||||
//
|
||||
// // layout of the closure record
|
||||
// let closure_data_layout = Layout::Struct(&[]);
|
||||
//
|
||||
// result = lambda_set_to_switch_make_branch_help(
|
||||
// env,
|
||||
// function_symbol,
|
||||
// closure_data_symbol,
|
||||
// closure_data_layout,
|
||||
// arg_symbols,
|
||||
// arg_layouts,
|
||||
// ret_layout,
|
||||
// assigned,
|
||||
// hole,
|
||||
// );
|
||||
//
|
||||
// result = with_hole(
|
||||
// env,
|
||||
// loc_expr.value,
|
||||
// fn_var,
|
||||
// procs,
|
||||
// layout_cache,
|
||||
// closure_data_symbol,
|
||||
// env.arena.alloc(result),
|
||||
// );
|
||||
}
|
||||
_ => {
|
||||
todo!("{:?}", full_layout)
|
||||
}
|
||||
|
@ -5461,13 +5384,11 @@ fn substitute_in_call<'a>(
|
|||
name,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
full_layout,
|
||||
specialization_id,
|
||||
} => substitute(subs, *name).map(|new| CallType::ByName {
|
||||
name: new,
|
||||
arg_layouts,
|
||||
ret_layout: *ret_layout,
|
||||
full_layout: *full_layout,
|
||||
specialization_id: *specialization_id,
|
||||
}),
|
||||
CallType::Foreign { .. } => None,
|
||||
|
@ -5930,13 +5851,10 @@ fn force_thunk<'a>(
|
|||
assigned: Symbol,
|
||||
hole: &'a Stmt<'a>,
|
||||
) -> Stmt<'a> {
|
||||
let full_layout = Layout::FunctionPointer(&[], env.arena.alloc(layout));
|
||||
|
||||
let call = self::Call {
|
||||
call_type: CallType::ByName {
|
||||
name: thunk_name,
|
||||
ret_layout: layout,
|
||||
full_layout,
|
||||
arg_layouts: &[],
|
||||
specialization_id: env.next_call_specialization_id(),
|
||||
},
|
||||
|
@ -6396,7 +6314,6 @@ fn call_by_name_help<'a>(
|
|||
// debug_assert!(!procs.module_thunks.contains(&proc_name), "{:?}", proc_name);
|
||||
|
||||
let top_level_layout = TopLevelFunctionLayout::new(env.arena, argument_layouts, *ret_layout);
|
||||
let function_layout = env.arena.alloc(top_level_layout).full();
|
||||
|
||||
// the arguments given to the function, stored in symbols
|
||||
let field_symbols = Vec::from_iter_in(
|
||||
|
@ -6438,7 +6355,6 @@ fn call_by_name_help<'a>(
|
|||
call_type: CallType::ByName {
|
||||
name: proc_name,
|
||||
ret_layout: *ret_layout,
|
||||
full_layout: function_layout,
|
||||
arg_layouts: argument_layouts,
|
||||
specialization_id: env.next_call_specialization_id(),
|
||||
},
|
||||
|
@ -6471,7 +6387,6 @@ fn call_by_name_help<'a>(
|
|||
call_type: CallType::ByName {
|
||||
name: proc_name,
|
||||
ret_layout: *ret_layout,
|
||||
full_layout: function_layout,
|
||||
arg_layouts: argument_layouts,
|
||||
specialization_id: env.next_call_specialization_id(),
|
||||
},
|
||||
|
@ -6524,7 +6439,6 @@ fn call_by_name_help<'a>(
|
|||
call_type: CallType::ByName {
|
||||
name: proc_name,
|
||||
ret_layout: *ret_layout,
|
||||
full_layout: function_layout,
|
||||
arg_layouts: argument_layouts,
|
||||
specialization_id: env.next_call_specialization_id(),
|
||||
},
|
||||
|
@ -6775,7 +6689,6 @@ fn call_specialized_proc<'a>(
|
|||
call_type: CallType::ByName {
|
||||
name: proc_name,
|
||||
ret_layout: function_layout.result,
|
||||
full_layout: function_layout.full(),
|
||||
arg_layouts: function_layout.arguments,
|
||||
specialization_id: env.next_call_specialization_id(),
|
||||
},
|
||||
|
@ -6795,14 +6708,13 @@ fn call_specialized_proc<'a>(
|
|||
call_type: CallType::ByName {
|
||||
name: proc_name,
|
||||
ret_layout: function_layout.result,
|
||||
full_layout: function_layout.full(),
|
||||
arg_layouts: function_layout.arguments,
|
||||
specialization_id: env.next_call_specialization_id(),
|
||||
},
|
||||
arguments: field_symbols,
|
||||
};
|
||||
|
||||
build_call(env, call, assigned, function_layout.full(), hole)
|
||||
build_call(env, call, assigned, function_layout.result, hole)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -6819,7 +6731,6 @@ fn call_specialized_proc<'a>(
|
|||
call_type: CallType::ByName {
|
||||
name: proc_name,
|
||||
ret_layout: function_layout.result,
|
||||
full_layout: function_layout.full(),
|
||||
arg_layouts: function_layout.arguments,
|
||||
specialization_id: env.next_call_specialization_id(),
|
||||
},
|
||||
|
@ -8091,13 +8002,10 @@ fn union_lambda_set_branch_help<'a>(
|
|||
}
|
||||
};
|
||||
|
||||
let full_layout = Layout::FunctionPointer(argument_layouts, env.arena.alloc(return_layout));
|
||||
|
||||
// build the call
|
||||
let call = self::Call {
|
||||
call_type: CallType::ByName {
|
||||
name: function_symbol,
|
||||
full_layout,
|
||||
ret_layout: return_layout,
|
||||
arg_layouts: argument_layouts,
|
||||
specialization_id: env.next_call_specialization_id(),
|
||||
|
@ -8212,12 +8120,9 @@ fn enum_lambda_set_branch<'a>(
|
|||
}
|
||||
};
|
||||
|
||||
let full_layout = Layout::FunctionPointer(argument_layouts, env.arena.alloc(return_layout));
|
||||
|
||||
let call = self::Call {
|
||||
call_type: CallType::ByName {
|
||||
name: function_symbol,
|
||||
full_layout,
|
||||
ret_layout: return_layout,
|
||||
arg_layouts: argument_layouts,
|
||||
specialization_id: env.next_call_specialization_id(),
|
||||
|
|
|
@ -791,6 +791,50 @@ impl<'a> LayoutCache<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn raw_from_var(
|
||||
&mut self,
|
||||
arena: &'a Bump,
|
||||
var: Variable,
|
||||
subs: &Subs,
|
||||
) -> Result<Layout<'a>, LayoutProblem> {
|
||||
// Store things according to the root Variable, to avoid duplicate work.
|
||||
let var = subs.get_root_key_without_compacting(var);
|
||||
|
||||
let cached_var = CachedVariable::new(var);
|
||||
|
||||
self.expand_to_fit(cached_var);
|
||||
|
||||
use CachedLayout::*;
|
||||
match self.layouts.probe_value(cached_var) {
|
||||
Cached(result) => Ok(result),
|
||||
Problem(problem) => Err(problem),
|
||||
NotCached => {
|
||||
let mut env = Env {
|
||||
arena,
|
||||
subs,
|
||||
seen: MutSet::default(),
|
||||
};
|
||||
|
||||
let result = Layout::from_var(&mut env, var);
|
||||
|
||||
// Don't actually cache. The layout cache is very hard to get right in the presence
|
||||
// of specialization, it's turned of for now so an invalid cache is never the cause
|
||||
// of a problem
|
||||
if false {
|
||||
let cached_layout = match &result {
|
||||
Ok(layout) => Cached(*layout),
|
||||
Err(problem) => Problem(problem.clone()),
|
||||
};
|
||||
|
||||
self.layouts
|
||||
.update_value(cached_var, |existing| existing.value = cached_layout);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_to_fit(&mut self, var: CachedVariable<'a>) {
|
||||
use ven_ena::unify::UnifyKey;
|
||||
|
||||
|
@ -1909,6 +1953,7 @@ impl LayoutId {
|
|||
|
||||
struct IdsByLayout<'a> {
|
||||
by_id: MutMap<Layout<'a>, u32>,
|
||||
toplevels_by_id: MutMap<crate::ir::TopLevelFunctionLayout<'a>, u32>,
|
||||
next_id: u32,
|
||||
}
|
||||
|
||||
|
@ -1925,6 +1970,7 @@ impl<'a> LayoutIds<'a> {
|
|||
// There's probably a nicer way to write it that still works.
|
||||
let ids = self.by_symbol.entry(symbol).or_insert_with(|| IdsByLayout {
|
||||
by_id: HashMap::with_capacity_and_hasher(1, default_hasher()),
|
||||
toplevels_by_id: Default::default(),
|
||||
next_id: 1,
|
||||
});
|
||||
|
||||
|
@ -1941,6 +1987,39 @@ impl<'a> LayoutIds<'a> {
|
|||
|
||||
LayoutId(answer)
|
||||
}
|
||||
|
||||
/// Returns a LayoutId which is unique for the given symbol and layout.
|
||||
/// If given the same symbol and same layout, returns the same LayoutId.
|
||||
pub fn get_toplevel<'b>(
|
||||
&mut self,
|
||||
symbol: Symbol,
|
||||
layout: &'b crate::ir::TopLevelFunctionLayout<'a>,
|
||||
) -> LayoutId {
|
||||
// Note: this function does some weird stuff to satisfy the borrow checker.
|
||||
// There's probably a nicer way to write it that still works.
|
||||
let ids = self.by_symbol.entry(symbol).or_insert_with(|| IdsByLayout {
|
||||
by_id: Default::default(),
|
||||
toplevels_by_id: HashMap::with_capacity_and_hasher(1, default_hasher()),
|
||||
next_id: 1,
|
||||
});
|
||||
|
||||
// Get the id associated with this layout, or default to next_id.
|
||||
let answer = ids
|
||||
.toplevels_by_id
|
||||
.get(&layout)
|
||||
.copied()
|
||||
.unwrap_or(ids.next_id);
|
||||
|
||||
// If we had to default to next_id, it must not have been found;
|
||||
// store the ID we're going to return and increment next_id.
|
||||
if answer == ids.next_id {
|
||||
ids.toplevels_by_id.insert(*layout, ids.next_id);
|
||||
|
||||
ids.next_id += 1;
|
||||
}
|
||||
|
||||
LayoutId(answer)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue