Merge remote-tracking branch 'origin/trunk' into list-unreachable

This commit is contained in:
Folkert 2022-07-04 19:21:31 +02:00
commit 6095dcff66
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
107 changed files with 10287 additions and 9870 deletions

View file

@ -163,7 +163,7 @@ impl<'a> DeclarationToIndex<'a> {
}
}
unreachable!(
"symbol/layout {:?} {:?} combo must be in DeclarationToIndex",
"symbol/layout {:?} {:#?} combo must be in DeclarationToIndex",
needle_symbol, needle_layout
)
}
@ -263,7 +263,7 @@ impl<'a> ParamMap<'a> {
self.declarations[index + i] = param;
}
self.visit_stmt(arena, proc.name, &proc.body);
self.visit_stmt(arena, proc.name.name(), &proc.body);
}
fn visit_proc_always_owned(
@ -282,7 +282,7 @@ impl<'a> ParamMap<'a> {
self.declarations[index + i] = param;
}
self.visit_stmt(arena, proc.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>) {
@ -501,11 +501,12 @@ impl<'a> BorrowInfState<'a> {
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
let ps = param_map
.get_symbol(*name, top_level)
.get_symbol(name.name(), top_level)
.expect("function is defined");
// the return value will be owned
@ -544,12 +545,14 @@ impl<'a> BorrowInfState<'a> {
let closure_layout = ProcLayout {
arguments: passed_function.argument_layouts,
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) {
Some(function_ps) => function_ps,
None => unreachable!(),
};
let function_ps =
match param_map.get_symbol(passed_function.name.name(), closure_layout) {
Some(function_ps) => function_ps,
None => unreachable!(),
};
match op {
ListMap { xs } => {
@ -743,12 +746,13 @@ impl<'a> BorrowInfState<'a> {
Stmt::Ret(z),
) = (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)
// 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)
}
}
@ -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();
self.update_param_set_symbols(ys);
self.current_proc = proc.name;
self.current_proc = proc.name.name();
// ensure that current_proc is in the owned map
self.owned.entry(proc.name).or_default();
self.owned.entry(proc.name.name()).or_default();
self.collect_stmt(param_map, &proc.body);
self.update_param_map_declaration(param_map, param_offset, proc.args.len());
@ -976,7 +980,7 @@ fn call_info_call<'a>(call: &crate::ir::Call<'a>, info: &mut CallInfo<'a>) {
match call.call_type {
ByName { name, .. } => {
info.keys.push(name);
info.keys.push(name.name());
}
Foreign { .. } => {}
LowLevel { .. } => {}

View file

@ -530,12 +530,43 @@ fn eq_tag_fields<'a>(
}
fn eq_boxed<'a>(
_root: &mut CodeGenHelp<'a>,
_ident_ids: &mut IdentIds,
_ctx: &mut Context<'a>,
_inner_layout: &'a Layout<'a>,
root: &mut CodeGenHelp<'a>,
ident_ids: &mut IdentIds,
ctx: &mut Context<'a>,
inner_layout: &'a Layout<'a>,
) -> Stmt<'a> {
todo!()
let a = root.create_symbol(ident_ids, "a");
let b = root.create_symbol(ident_ids, "b");
let result = root.create_symbol(ident_ids, "result");
let a_expr = Expr::ExprUnbox { symbol: ARG_1 };
let b_expr = Expr::ExprUnbox { symbol: ARG_2 };
let eq_call_expr = root
.call_specialized_op(ident_ids, ctx, *inner_layout, root.arena.alloc([a, b]))
.unwrap();
Stmt::Let(
a,
a_expr,
*inner_layout,
root.arena.alloc(
//
Stmt::Let(
b,
b_expr,
*inner_layout,
root.arena.alloc(
//
Stmt::Let(
result,
eq_call_expr,
LAYOUT_BOOL,
root.arena.alloc(Stmt::Ret(result)),
),
),
),
),
)
}
/// List equality

View file

@ -8,7 +8,7 @@ use crate::ir::{
Call, CallSpecId, CallType, Expr, HostExposedLayouts, JoinPointId, ModifyRc, Proc, ProcLayout,
SelfRecursive, Stmt, UpdateModeId,
};
use crate::layout::{Builtin, Layout, UnionLayout};
use crate::layout::{Builtin, CapturesNiche, LambdaName, Layout, UnionLayout};
mod equality;
mod refcount;
@ -170,7 +170,7 @@ impl<'a> CodeGenHelp<'a> {
let arg_layouts = self.arena.alloc([layout]);
let expr = Expr::Call(Call {
call_type: CallType::ByName {
name: proc_name,
name: LambdaName::no_niche(proc_name),
ret_layout,
arg_layouts,
specialization_id: CallSpecId::BACKEND_DUMMY,
@ -262,7 +262,7 @@ impl<'a> CodeGenHelp<'a> {
Some(Expr::Call(Call {
call_type: CallType::ByName {
name: proc_name,
name: LambdaName::no_niche(proc_name),
ret_layout,
arg_layouts,
specialization_id: CallSpecId::BACKEND_DUMMY,
@ -286,11 +286,11 @@ impl<'a> CodeGenHelp<'a> {
&mut self,
ident_ids: &mut IdentIds,
ctx: &mut Context<'a>,
layout: Layout<'a>,
orig_layout: Layout<'a>,
) -> Symbol {
use HelperOp::*;
let layout = self.replace_rec_ptr(ctx, layout);
let layout = self.replace_rec_ptr(ctx, orig_layout);
let found = self
.specializations
@ -343,7 +343,7 @@ impl<'a> CodeGenHelp<'a> {
};
self.specializations[spec_index].proc = Some(Proc {
name: proc_symbol,
name: LambdaName::no_niche(proc_symbol),
args,
body,
closure_data_layout: None,
@ -375,19 +375,23 @@ impl<'a> CodeGenHelp<'a> {
HelperOp::Inc => ProcLayout {
arguments: self.arena.alloc([*layout, self.layout_isize]),
result: LAYOUT_UNIT,
captures_niche: CapturesNiche::no_niche(),
},
HelperOp::Dec => ProcLayout {
arguments: self.arena.alloc([*layout]),
result: LAYOUT_UNIT,
captures_niche: CapturesNiche::no_niche(),
},
HelperOp::Reset => ProcLayout {
arguments: self.arena.alloc([*layout]),
result: *layout,
captures_niche: CapturesNiche::no_niche(),
},
HelperOp::DecRef(_) => unreachable!("No generated Proc for DecRef"),
HelperOp::Eq => ProcLayout {
arguments: self.arena.alloc([*layout, *layout]),
result: LAYOUT_BOOL,
captures_niche: CapturesNiche::no_niche(),
},
};
@ -450,7 +454,9 @@ impl<'a> CodeGenHelp<'a> {
layout
}
Layout::Boxed(inner) => self.replace_rec_ptr(ctx, *inner),
Layout::Boxed(inner) => {
Layout::Boxed(self.arena.alloc(self.replace_rec_ptr(ctx, *inner)))
}
Layout::LambdaSet(lambda_set) => {
self.replace_rec_ptr(ctx, lambda_set.runtime_representation())

View file

@ -129,7 +129,9 @@ pub fn refcount_generic<'a>(
Layout::RecursivePointer => unreachable!(
"We should never call a refcounting helper on a RecursivePointer layout directly"
),
Layout::Boxed(_) => rc_todo(),
Layout::Boxed(inner_layout) => {
refcount_boxed(root, ident_ids, ctx, &layout, inner_layout, structure)
}
}
}
@ -343,7 +345,7 @@ pub fn is_rc_implemented_yet(layout: &Layout) -> bool {
is_rc_implemented_yet(&lambda_set.runtime_representation())
}
Layout::RecursivePointer => true,
Layout::Boxed(_) => false,
Layout::Boxed(_) => true,
}
}
@ -1465,3 +1467,66 @@ fn refcount_tag_fields<'a>(
stmt
}
fn refcount_boxed<'a>(
root: &mut CodeGenHelp<'a>,
ident_ids: &mut IdentIds,
ctx: &mut Context<'a>,
layout: &Layout,
inner_layout: &'a Layout,
outer: Symbol,
) -> Stmt<'a> {
let arena = root.arena;
//
// modify refcount of the inner and outer structures
// RC on inner first, to avoid use-after-free for Dec
// We're defining statements in reverse, so define outer first
//
let rc_ptr = root.create_symbol(ident_ids, "rc_ptr");
let alignment = layout.alignment_bytes(root.target_info);
let ret_stmt = rc_return_stmt(root, ident_ids, ctx);
let modify_outer = modify_refcount(
root,
ident_ids,
ctx,
rc_ptr,
alignment,
arena.alloc(ret_stmt),
);
let get_rc_and_modify_outer = rc_ptr_from_data_ptr(
root,
ident_ids,
outer,
rc_ptr,
false,
arena.alloc(modify_outer),
);
if inner_layout.is_refcounted() && !ctx.op.is_decref() {
let inner = root.create_symbol(ident_ids, "inner");
let inner_expr = Expr::ExprUnbox { symbol: outer };
let mod_inner_unit = root.create_symbol(ident_ids, "mod_inner_unit");
let mod_inner_args = refcount_args(root, ctx, inner);
let mod_inner_expr = root
.call_specialized_op(ident_ids, ctx, *inner_layout, mod_inner_args)
.unwrap();
Stmt::Let(
inner,
inner_expr,
*inner_layout,
arena.alloc(Stmt::Let(
mod_inner_unit,
mod_inner_expr,
LAYOUT_UNIT,
arena.alloc(get_rc_and_modify_outer),
)),
)
} else {
get_rc_and_modify_outer
}
}

View file

@ -564,12 +564,13 @@ impl<'a> Context<'a> {
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
let ps = self
.param_map
.get_symbol(*name, top_level)
.get_symbol(name.name(), top_level)
.expect("function is defined");
let v = Expr::Call(crate::ir::Call {
@ -614,11 +615,12 @@ impl<'a> Context<'a> {
let function_layout = ProcLayout {
arguments: passed_function.argument_layouts,
result: passed_function.return_layout,
captures_niche: passed_function.name.captures_niche(),
};
let function_ps = match self
.param_map
.get_symbol(passed_function.name, function_layout)
.get_symbol(passed_function.name.name(), function_layout)
{
Some(function_ps) => function_ps,
None => unreachable!(),
@ -1406,7 +1408,7 @@ fn visit_proc<'a, 'i>(
proc: &mut Proc<'a>,
layout: ProcLayout<'a>,
) {
let params = match param_map.get_symbol(proc.name, layout) {
let params = match param_map.get_symbol(proc.name.name(), layout) {
Some(slice) => slice,
None => Vec::from_iter_in(
proc.args.iter().cloned().map(|(layout, symbol)| Param {

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,6 @@ use roc_module::ident::{Lowercase, TagName};
use roc_module::symbol::{Interns, Symbol};
use roc_problem::can::RuntimeError;
use roc_target::{PtrWidth, TargetInfo};
use roc_types::pretty_print::ResolvedLambdaSet;
use roc_types::subs::{
self, Content, FlatType, Label, RecordFields, Subs, UnionTags, UnsortedUnionLabels, Variable,
};
@ -226,7 +225,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);
impl FieldOrderHash {
@ -248,7 +247,7 @@ impl FieldOrderHash {
}
/// 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> {
Builtin(Builtin<'a>),
Struct {
@ -270,7 +269,7 @@ pub enum Layout<'a> {
RecursivePointer,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum UnionLayout<'a> {
/// A non-recursive tag union
/// e.g. `Result a e : [Ok a, Err e]`
@ -693,7 +692,74 @@ impl std::fmt::Debug for LambdaSet<'_> {
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
/// Sometimes we can end up with lambdas of the same name and different captures in the same
/// lambda set, like `fun` having lambda set `[[thunk U64, thunk U8]]` due to the following program:
///
/// ```roc
/// capture : _ -> ({} -> Str)
/// capture = \val ->
/// thunk = \{} -> Num.toStr val
/// thunk
///
/// fun = \x ->
/// when x is
/// True -> capture 123u64
/// False -> capture 18u8
/// ```
///
/// By recording the captures layouts this lambda expects in its identifier, we can distinguish
/// between such differences when constructing closure capture data.
///
/// See also https://github.com/rtfeldman/roc/issues/3336.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct CapturesNiche<'a>(&'a [Layout<'a>]);
impl CapturesNiche<'_> {
pub fn no_niche() -> Self {
Self(&[])
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct LambdaName<'a> {
name: Symbol,
captures_niche: CapturesNiche<'a>,
}
impl<'a> LambdaName<'a> {
#[inline(always)]
pub fn name(&self) -> Symbol {
self.name
}
#[inline(always)]
pub fn captures_niche(&self) -> CapturesNiche<'a> {
self.captures_niche
}
#[inline(always)]
pub fn no_captures(&self) -> bool {
self.captures_niche.0.is_empty()
}
#[inline(always)]
pub fn no_niche(name: Symbol) -> Self {
Self {
name,
captures_niche: CapturesNiche::no_niche(),
}
}
#[inline(always)]
pub fn replace_name(&self, name: Symbol) -> Self {
Self {
name,
captures_niche: self.captures_niche,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct LambdaSet<'a> {
/// collection of function names and their closure arguments
pub set: &'a [(Symbol, &'a [Layout<'a>])],
@ -741,23 +807,57 @@ impl<'a> LambdaSet<'a> {
}
}
pub fn member_does_not_need_closure_argument(&self, function_symbol: Symbol) -> bool {
match self.layout_for_member(function_symbol) {
ClosureRepresentation::Union {
alphabetic_order_fields,
..
} => alphabetic_order_fields.is_empty(),
ClosureRepresentation::AlphabeticOrderStruct(fields) => fields.is_empty(),
ClosureRepresentation::Other(_) => false,
pub fn iter_set(&self) -> impl ExactSizeIterator<Item = LambdaName<'a>> {
self.set.iter().map(|(name, captures_layouts)| LambdaName {
name: *name,
captures_niche: CapturesNiche(captures_layouts),
})
}
pub fn layout_for_member_with_lambda_name(
&self,
lambda_name: LambdaName,
) -> ClosureRepresentation<'a> {
debug_assert!(self.contains(lambda_name.name));
let comparator = |other_name: Symbol, other_captures_layouts: &[Layout]| {
other_name == lambda_name.name
&& other_captures_layouts
.iter()
.eq(lambda_name.captures_niche.0)
};
self.layout_for_member(comparator)
}
/// Finds an alias name for a possible-multimorphic lambda variant in the lambda set.
pub fn find_lambda_name(
&self,
function_symbol: Symbol,
captures_layouts: &[Layout],
) -> LambdaName<'a> {
debug_assert!(self.contains(function_symbol), "function symbol not in set");
let comparator = |other_name: Symbol, other_captures_layouts: &[Layout]| {
other_name == function_symbol && other_captures_layouts.iter().eq(captures_layouts)
};
let (name, layouts) = self
.set
.iter()
.find(|(name, layouts)| comparator(*name, layouts))
.expect("no lambda set found");
LambdaName {
name: *name,
captures_niche: CapturesNiche(layouts),
}
}
pub fn layout_for_member(&self, function_symbol: Symbol) -> ClosureRepresentation<'a> {
debug_assert!(
self.set.iter().any(|(s, _)| *s == function_symbol),
"function symbol not in set"
);
fn layout_for_member<F>(&self, comparator: F) -> ClosureRepresentation<'a>
where
F: Fn(Symbol, &[Layout]) -> bool,
{
match self.representation {
Layout::Union(union) => {
// here we rely on the fact that a union in a closure would be stored in a one-element record.
@ -766,17 +866,19 @@ impl<'a> LambdaSet<'a> {
UnionLayout::NonRecursive(_) => {
// get the fields from the set, where they are sorted in alphabetic order
// (and not yet sorted by their alignment)
let (index, (_, fields)) = self
let (index, (name, fields)) = self
.set
.iter()
.enumerate()
.find(|(_, (s, _))| *s == function_symbol)
.find(|(_, (s, layouts))| comparator(*s, layouts))
.unwrap();
let closure_name = *name;
ClosureRepresentation::Union {
tag_id: index as TagIdIntType,
alphabetic_order_fields: fields,
closure_name: function_symbol,
closure_name,
union_layout: *union,
}
}
@ -793,12 +895,14 @@ impl<'a> LambdaSet<'a> {
}
}
Layout::Struct { .. } => {
debug_assert_eq!(self.set.len(), 1);
// get the fields from the set, where they are sorted in alphabetic order
// (and not yet sorted by their alignment)
let (_, fields) = self
.set
.iter()
.find(|(s, _)| *s == function_symbol)
.find(|(s, layouts)| comparator(*s, layouts))
.unwrap();
ClosureRepresentation::AlphabeticOrderStruct(fields)
@ -846,32 +950,86 @@ impl<'a> LambdaSet<'a> {
closure_var: Variable,
target_info: TargetInfo,
) -> Result<Self, LayoutProblem> {
match roc_types::pretty_print::resolve_lambda_set(subs, closure_var) {
match resolve_lambda_set(subs, closure_var) {
ResolvedLambdaSet::Set(mut lambdas) => {
// sort the tags; make sure ordering stays intact!
lambdas.sort();
lambdas.sort_by_key(|(sym, _)| *sym);
let mut set = Vec::with_capacity_in(lambdas.len(), arena);
let mut set: Vec<(Symbol, &[Layout])> = Vec::with_capacity_in(lambdas.len(), arena);
let mut set_with_variables: std::vec::Vec<(Symbol, std::vec::Vec<Variable>)> =
std::vec::Vec::with_capacity(lambdas.len());
let mut env = Env {
arena,
subs,
seen: Vec::new_in(arena),
target_info,
};
let mut last_function_symbol = None;
let mut lambdas_it = lambdas.iter().peekable();
for (function_symbol, variables) in lambdas.iter() {
let mut has_duplicate_lambda_names = false;
while let Some((function_symbol, variables)) = lambdas_it.next() {
let mut arguments = Vec::with_capacity_in(variables.len(), arena);
let mut env = Env {
arena,
subs,
seen: Vec::new_in(arena),
target_info,
};
for var in variables {
arguments.push(Layout::from_var(&mut env, *var)?);
}
set.push((*function_symbol, arguments.into_bump_slice()));
let arguments = arguments.into_bump_slice();
let is_multimorphic = match (last_function_symbol, lambdas_it.peek()) {
(None, None) => false,
(Some(sym), None) | (None, Some((sym, _))) => function_symbol == sym,
(Some(sym1), Some((sym2, _))) => {
function_symbol == sym1 || function_symbol == sym2
}
};
has_duplicate_lambda_names = has_duplicate_lambda_names || is_multimorphic;
set.push((*function_symbol, arguments));
set_with_variables.push((*function_symbol, variables.to_vec()));
last_function_symbol = Some(function_symbol);
}
let representation =
arena.alloc(Self::make_representation(arena, subs, lambdas, target_info));
let (set, set_with_variables) = if has_duplicate_lambda_names {
// If we have a lambda set with duplicate names, then we sort first by name,
// and break ties by sorting on the layout. We need to do this again since the
// first sort would not have sorted on the layout.
// 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)
});
// Remove duplicate lambda captures layouts unification can't see as
// duplicates, for example [[Thunk {a: Str}, Thunk [A Str]]], each of which are
// newtypes over the lambda layout `Thunk Str`.
joined.dedup_by_key(|((name, captures), _)| (*name, *captures));
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(
arena,
subs,
set_with_variables,
target_info,
));
Ok(LambdaSet {
set: set.into_bump_slice(),
@ -951,7 +1109,41 @@ impl<'a> LambdaSet<'a> {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
enum ResolvedLambdaSet {
Set(std::vec::Vec<(Symbol, std::vec::Vec<Variable>)>),
/// TODO: figure out if this can happen in a correct program, or is the result of a bug in our
/// compiler. See https://github.com/rtfeldman/roc/issues/3163.
Unbound,
}
fn resolve_lambda_set(subs: &Subs, mut var: Variable) -> ResolvedLambdaSet {
let mut set = vec![];
loop {
match subs.get_content_without_compacting(var) {
Content::LambdaSet(subs::LambdaSet {
solved,
recursion_var: _,
unspecialized,
}) => {
debug_assert!(
unspecialized.is_empty(),
"unspecialized lambda sets left over during resolution: {:?}",
roc_types::subs::SubsFmtContent(subs.get_content_without_compacting(var), subs),
);
roc_types::pretty_print::push_union(subs, solved, &mut set);
return ResolvedLambdaSet::Set(set);
}
Content::RecursionVar { structure, .. } => {
var = *structure;
}
Content::FlexVar(_) => return ResolvedLambdaSet::Unbound,
c => internal_error!("called with a non-lambda set {:?}", c),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Builtin<'a> {
Int(IntWidth),
Float(FloatWidth),

View file

@ -97,7 +97,6 @@ fn function_s<'a, 'i>(
Expr::Tag {
tag_layout,
tag_id,
tag_name,
arguments,
} if may_reuse(*tag_layout, *tag_id, c) => {
// for now, always overwrite the tag ID just to be sure
@ -109,7 +108,6 @@ fn function_s<'a, 'i>(
update_tag_id,
tag_layout: *tag_layout,
tag_id: *tag_id,
tag_name: tag_name.clone(),
arguments,
};
let new_stmt = Let(*symbol, new_expr, *layout, continuation);

View file

@ -1,7 +1,7 @@
#![allow(clippy::manual_map)]
use crate::ir::{CallType, Expr, JoinPointId, Param, Stmt};
use crate::layout::Layout;
use crate::layout::{LambdaName, Layout};
use bumpalo::collections::Vec;
use bumpalo::Bump;
use roc_module::symbol::Symbol;
@ -31,7 +31,7 @@ use roc_module::symbol::Symbol;
pub fn make_tail_recursive<'a>(
arena: &'a Bump,
id: JoinPointId,
needle: Symbol,
needle: LambdaName,
stmt: Stmt<'a>,
args: &'a [(Layout<'a>, Symbol, Symbol)],
ret_layout: Layout,
@ -71,7 +71,7 @@ fn insert_jumps<'a>(
arena: &'a Bump,
stmt: &'a Stmt<'a>,
goal_id: JoinPointId,
needle: Symbol,
needle: LambdaName,
needle_arguments: &'a [(Layout<'a>, Symbol, Symbol)],
needle_result: Layout,
) -> 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
// 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!
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);
needle == function_name && it.eq(arguments.iter()) && needle_result == result
};