diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index 5a5261b6a5..419158288a 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -46,7 +46,14 @@ pub fn infer_borrow<'a>( // component (in top-sorted order, from primitives (std-lib) to main) let successor_map = &make_successor_mapping(arena, procs); - let successors = move |key: &Symbol| successor_map[key].iter().copied(); + let successors = move |key: &Symbol| { + let slice = match successor_map.get(key) { + None => &[] as &[_], + Some(s) => s.as_slice(), + }; + + slice.iter().copied() + }; let mut symbols = Vec::with_capacity_in(procs.len(), arena); symbols.extend(procs.keys().map(|x| x.0)); @@ -217,7 +224,10 @@ impl<'a> DeclarationToIndex<'a> { } } } - unreachable!("symbol/layout combo must be in DeclarationToIndex") + unreachable!( + "symbol/layout {:?} {:?} combo must be in DeclarationToIndex", + needle_symbol, needle_layout + ) } } diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index a39785e684..5fb8473a77 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -6159,6 +6159,38 @@ fn build_call<'a>( Stmt::Let(assigned, Expr::Call(call), return_layout, hole) } +/// See https://github.com/rtfeldman/roc/issues/1549 +/// +/// What happened is that a function has a type error, but the arguments are not processed. +/// That means specializations were missing. Normally that is not a problem, but because +/// of our closure strategy, internal functions can "leak". That's what happened here. +/// +/// The solution is to evaluate the arguments as normal, and only when calling the function give an error +fn evaluate_arguments_then_runtime_error<'a>( + env: &mut Env<'a, '_>, + procs: &mut Procs<'a>, + layout_cache: &mut LayoutCache<'a>, + msg: String, + loc_args: std::vec::Vec<(Variable, Located)>, +) -> Stmt<'a> { + let arena = env.arena; + + // eventually we will throw this runtime error + let result = Stmt::RuntimeError(env.arena.alloc(msg)); + + // but, we also still evaluate and specialize the arguments to give better error messages + let arg_symbols = Vec::from_iter_in( + loc_args + .iter() + .map(|(_, arg_expr)| possible_reuse_symbol(env, procs, &arg_expr.value)), + arena, + ) + .into_bump_slice(); + + let iter = loc_args.into_iter().rev().zip(arg_symbols.iter().rev()); + assign_to_symbols(env, procs, layout_cache, iter, result) +} + #[allow(clippy::too_many_arguments)] fn call_by_name<'a>( env: &mut Env<'a, '_>, @@ -6177,14 +6209,16 @@ fn call_by_name<'a>( "Hit an unresolved type variable {:?} when creating a layout for {:?} (var {:?})", var, proc_name, fn_var ); - Stmt::RuntimeError(env.arena.alloc(msg)) + + evaluate_arguments_then_runtime_error(env, procs, layout_cache, msg, loc_args) } Err(LayoutProblem::Erroneous) => { let msg = format!( "Hit an erroneous type when creating a layout for {:?}", proc_name ); - Stmt::RuntimeError(env.arena.alloc(msg)) + + evaluate_arguments_then_runtime_error(env, procs, layout_cache, msg, loc_args) } Ok(RawFunctionLayout::Function(arg_layouts, lambda_set, ret_layout)) => { if procs.module_thunks.contains(&proc_name) { diff --git a/compiler/types/src/subs.rs b/compiler/types/src/subs.rs index 4aca1a9eb5..6625ab0630 100644 --- a/compiler/types/src/subs.rs +++ b/compiler/types/src/subs.rs @@ -327,6 +327,14 @@ fn subs_fmt_desc(this: &Descriptor, subs: &Subs, f: &mut fmt::Formatter) -> fmt: write!(f, " m: {:?}", &this.mark) } +pub struct SubsFmtContent<'a>(pub &'a Content, pub &'a Subs); + +impl<'a> fmt::Debug for SubsFmtContent<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + subs_fmt_content(self.0, self.1, f) + } +} + fn subs_fmt_content(this: &Content, subs: &Subs, f: &mut fmt::Formatter) -> fmt::Result { match this { Content::FlexVar(name) => write!(f, "Flex({:?})", name), @@ -345,6 +353,14 @@ fn subs_fmt_content(this: &Content, subs: &Subs, f: &mut fmt::Formatter) -> fmt: } } +pub struct SubsFmtFlatType<'a>(pub &'a FlatType, pub &'a Subs); + +impl<'a> fmt::Debug for SubsFmtFlatType<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + subs_fmt_flat_type(self.0, self.1, f) + } +} + fn subs_fmt_flat_type(this: &FlatType, subs: &Subs, f: &mut fmt::Formatter) -> fmt::Result { match this { FlatType::Apply(name, arguments) => { diff --git a/compiler/unify/src/unify.rs b/compiler/unify/src/unify.rs index 169559476d..51771efe07 100644 --- a/compiler/unify/src/unify.rs +++ b/compiler/unify/src/unify.rs @@ -1076,8 +1076,8 @@ fn unify_flat_type( // any other combination is a mismatch mismatch!( "Trying to unify two flat types that are incompatible: {:?} ~ {:?}", - other1, - other2 + roc_types::subs::SubsFmtFlatType(other1, subs), + roc_types::subs::SubsFmtFlatType(other2, subs) ) } }