From 3b458309c6f45adda6eb4ab54579c77a1572ff65 Mon Sep 17 00:00:00 2001 From: Folkert Date: Thu, 25 Mar 2021 16:56:47 +0100 Subject: [PATCH] WIP emit runtime error functions on specialization failure --- compiler/load/src/file.rs | 7 +- compiler/mono/src/ir.rs | 118 ++++++++++++++++++------ compiler/test_gen/src/gen_primitives.rs | 19 ++++ 3 files changed, 111 insertions(+), 33 deletions(-) diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index fc6177c4bd..842b23799e 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -3773,12 +3773,7 @@ fn make_specializations<'a>( // TODO: for now this final specialization pass is sequential, // with no parallelization at all. We should try to parallelize // this, but doing so will require a redesign of Procs. - procs = roc_mono::ir::specialize_all( - &mut mono_env, - procs, - &mut layout_cache, - // &finished_info.vars_by_symbol, - ); + procs = roc_mono::ir::specialize_all(&mut mono_env, procs, &mut layout_cache); let external_specializations_requested = procs.externals_we_need.clone(); let procedures = procs.get_specialized_procs_without_rc(mono_env.arena); diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index de2c6944c6..0188db668b 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -562,6 +562,7 @@ impl<'a> Procs<'a> { "TODO generate a RuntimeError message for {:?}", error ); + dbg!(symbol); self.runtime_errors .insert(symbol, env.arena.alloc(error_msg)); panic!(); @@ -673,6 +674,7 @@ impl<'a> Procs<'a> { Err(error) => { let error_msg = format!("TODO generate a RuntimeError message for {:?}", error); + dbg!(symbol); self.runtime_errors .insert(symbol, env.arena.alloc(error_msg)); panic!(); @@ -1696,13 +1698,15 @@ pub fn specialize_all<'a>( Ok((proc, layout)) => { procs.specialized.insert((name, layout), Done(proc)); } - Err(error) => { - let error_msg = env.arena.alloc(format!( - "TODO generate a RuntimeError message for {:?}", - error - )); + Err(SpecializeFailure { + problem: _, + attempted_layout, + }) => { + let proc = generate_runtime_error_function(env, name, attempted_layout); - procs.runtime_errors.insert(name, error_msg); + procs + .specialized + .insert((name, attempted_layout), Done(proc)); } } } @@ -1774,6 +1778,47 @@ pub fn specialize_all<'a>( procs } +fn generate_runtime_error_function<'a>( + env: &mut Env<'a, '_>, + name: Symbol, + layout: Layout<'a>, +) -> Proc<'a> { + let (arg_layouts, ret_layout) = match layout { + Layout::FunctionPointer(a, r) => (a, *r), + _ => (&[] as &[_], layout), + }; + + let mut args = Vec::with_capacity_in(arg_layouts.len(), env.arena); + + for arg in arg_layouts { + args.push((*arg, env.unique_symbol())); + } + + let mut msg = bumpalo::collections::string::String::with_capacity_in(80, env.arena); + use std::fmt::Write; + write!( + &mut msg, + "The {:?} function could not be generated, likely due to a type error.", + name + ) + .unwrap(); + + eprintln!("emitted runtime error function {:?}", &msg); + + let runtime_error = Stmt::RuntimeError(msg.into_bump_str()); + + Proc { + name, + args: args.into_bump_slice(), + body: runtime_error, + closure_data_layout: None, + ret_layout, + is_self_recursive: SelfRecursive::NotSelfRecursive, + must_own_arguments: false, + host_exposed_layouts: HostExposedLayouts::NotHostExposed, + } +} + fn specialize_external<'a>( env: &mut Env<'a, '_>, procs: &mut Procs<'a>, @@ -2270,6 +2315,14 @@ fn build_specialized_proc<'a>( } } +#[derive(Debug)] +struct SpecializeFailure<'a> { + /// The layout we attempted to create + attempted_layout: Layout<'a>, + /// The problem we ran into while creating it + problem: LayoutProblem, +} + fn specialize<'a>( env: &mut Env<'a, '_>, procs: &mut Procs<'a>, @@ -2277,7 +2330,7 @@ fn specialize<'a>( layout_cache: &mut LayoutCache<'a>, pending: PendingSpecialization, partial_proc: PartialProc<'a>, -) -> Result<(Proc<'a>, Layout<'a>), LayoutProblem> { +) -> Result<(Proc<'a>, Layout<'a>), SpecializeFailure<'a>> { let PendingSpecialization { solved_type, host_exposed_aliases, @@ -2321,7 +2374,7 @@ fn specialize_solved_type<'a>( solved_type: SolvedType, host_exposed_aliases: MutMap, partial_proc: PartialProc<'a>, -) -> Result<(Proc<'a>, Layout<'a>), LayoutProblem> { +) -> Result<(Proc<'a>, Layout<'a>), SpecializeFailure<'a>> { // add the specializations that other modules require of us use roc_solve::solve::instantiate_rigids; @@ -2330,6 +2383,10 @@ fn specialize_solved_type<'a>( let fn_var = introduce_solved_type_to_subs(env, &solved_type); + let attempted_layout = layout_cache + .from_var(&env.arena, fn_var, env.subs) + .unwrap_or_else(|err| panic!("TODO handle invalid function {:?}", err)); + // make sure rigid variables in the annotation are converted to flex variables instantiate_rigids(env.subs, partial_proc.annotation); @@ -2353,17 +2410,24 @@ fn specialize_solved_type<'a>( match specialized { Ok(proc) => { - let layout = layout_cache - .from_var(&env.arena, fn_var, env.subs) - .unwrap_or_else(|err| panic!("TODO handle invalid function {:?}", err)); + debug_assert_eq!( + attempted_layout, + layout_cache + .from_var(&env.arena, fn_var, env.subs) + .unwrap_or_else(|err| panic!("TODO handle invalid function {:?}", err)) + ); + env.subs.rollback_to(snapshot); layout_cache.rollback_to(cache_snapshot); - Ok((proc, layout)) + Ok((proc, attempted_layout)) } Err(error) => { env.subs.rollback_to(snapshot); layout_cache.rollback_to(cache_snapshot); - Err(error) + Err(SpecializeFailure { + problem: error, + attempted_layout, + }) } } } @@ -5893,6 +5957,20 @@ fn call_by_name<'a>( // Register a pending_specialization for this function match layout_cache.from_var(env.arena, fn_var, env.subs) { + Err(LayoutProblem::UnresolvedTypeVar(var)) => { + let msg = format!( + "Hit an unresolved type variable {:?} when creating a layout for {:?} (var {:?})", + var, proc_name, fn_var + ); + Stmt::RuntimeError(env.arena.alloc(msg)) + } + Err(LayoutProblem::Erroneous) => { + let msg = format!( + "Hit an erroneous type when creating a layout for {:?}", + proc_name + ); + Stmt::RuntimeError(env.arena.alloc(msg)) + } Ok(layout) => { // Build the CallByName node let arena = env.arena; @@ -6204,20 +6282,6 @@ fn call_by_name<'a>( } } } - Err(LayoutProblem::UnresolvedTypeVar(var)) => { - let msg = format!( - "Hit an unresolved type variable {:?} when creating a layout for {:?} (var {:?})", - var, proc_name, fn_var - ); - Stmt::RuntimeError(env.arena.alloc(msg)) - } - Err(LayoutProblem::Erroneous) => { - let msg = format!( - "Hit an erroneous type when creating a layout for {:?}", - proc_name - ); - Stmt::RuntimeError(env.arena.alloc(msg)) - } } } diff --git a/compiler/test_gen/src/gen_primitives.rs b/compiler/test_gen/src/gen_primitives.rs index aa277f8a6a..92709468c8 100644 --- a/compiler/test_gen/src/gen_primitives.rs +++ b/compiler/test_gen/src/gen_primitives.rs @@ -2276,3 +2276,22 @@ fn function_malformed_pattern() { i64 ); } + +#[test] +#[should_panic( + expected = "Shadowing { original_region: |L 3-3, C 4-5|, shadow: |L 5-5, C 6-7| Ident(\\\"x\\\") }" +)] +fn call_invalid_layout() { + assert_evals_to!( + indoc!( + r#" + f : I64 -> I64 + f = \x -> x + + f {} + "# + ), + 3, + i64 + ); +}