From 5df489ba23ee03515553224f0333bc958092d230 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 10 Jul 2022 19:17:51 +0200 Subject: [PATCH] turn toplevel expects into inline expects --- crates/compiler/can/src/expr.rs | 55 +++++++++++++++++++++- crates/compiler/gen_llvm/src/llvm/build.rs | 4 +- crates/compiler/load_internal/src/file.rs | 4 ++ 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/crates/compiler/can/src/expr.rs b/crates/compiler/can/src/expr.rs index 5c0c5c8a59..7aee3a61c7 100644 --- a/crates/compiler/can/src/expr.rs +++ b/crates/compiler/can/src/expr.rs @@ -10,7 +10,7 @@ use crate::num::{ use crate::pattern::{canonicalize_pattern, BindingsFromPattern, Pattern}; use crate::procedure::References; use crate::scope::Scope; -use roc_collections::soa::Index; +use roc_collections::soa::{Index, Slice}; use roc_collections::{SendMap, VecMap, VecSet}; use roc_error_macros::internal_error; use roc_module::called_via::CalledVia; @@ -2393,3 +2393,56 @@ fn get_lookup_symbols(expr: &Expr, var_store: &mut VarStore) -> Vec<(Symbol, Var symbols } + +pub fn convert_toplevel_expect(mut loc_expr: Loc) -> Loc { + enum StoredDef { + NonRecursive(Region, Box), + Recursive(Region, Vec, IllegalCycleMark), + } + + let mut stack = vec![]; + let mut lookups_in_cond = vec![]; + + loop { + match loc_expr.value { + Expr::LetNonRec(boxed_def, remainder) => { + lookups_in_cond.extend(boxed_def.pattern_vars.iter().map(|(a, b)| (*a, *b))); + + stack.push(StoredDef::NonRecursive(loc_expr.region, boxed_def)); + loc_expr = *remainder; + } + Expr::LetRec(defs, remainder, mark) => { + for def in &defs { + lookups_in_cond.extend(def.pattern_vars.iter().map(|(a, b)| (*a, *b))); + } + + stack.push(StoredDef::Recursive(loc_expr.region, defs, mark)); + loc_expr = *remainder; + } + _ => break, + } + } + + let expect_region = loc_expr.region; + let expect = Expr::Expect { + loc_condition: Box::new(loc_expr), + loc_continuation: Box::new(Loc::at_zero(Expr::EmptyRecord)), + lookups_in_cond, + }; + + let mut loc_expr = Loc::at(expect_region, expect); + + for stored in stack { + match stored { + StoredDef::NonRecursive(region, boxed_def) => { + loc_expr = Loc::at(region, Expr::LetNonRec(boxed_def, Box::new(loc_expr))); + } + StoredDef::Recursive(region, defs, illegal_cycle_mark) => { + let let_rec = Expr::LetRec(defs, Box::new(loc_expr), illegal_cycle_mark); + loc_expr = Loc::at(region, let_rec); + } + } + } + + loc_expr +} diff --git a/crates/compiler/gen_llvm/src/llvm/build.rs b/crates/compiler/gen_llvm/src/llvm/build.rs index 23b41fb931..2673ef2556 100644 --- a/crates/compiler/gen_llvm/src/llvm/build.rs +++ b/crates/compiler/gen_llvm/src/llvm/build.rs @@ -4190,7 +4190,7 @@ pub fn build_procedures_expose_expects<'a, 'ctx, 'env>( let expects: Vec<_> = procedures .keys() .filter_map(|(symbol, proc_layout)| { - if proc_layout.arguments.is_empty() && proc_layout.result == Layout::bool() { + if proc_layout.arguments.is_empty() && proc_layout.result == Layout::UNIT { Some(*symbol) } else { None @@ -4210,7 +4210,7 @@ pub fn build_procedures_expose_expects<'a, 'ctx, 'env>( let top_level = ProcLayout { arguments: &[], - result: Layout::bool(), + result: Layout::UNIT, captures_niche, }; diff --git a/crates/compiler/load_internal/src/file.rs b/crates/compiler/load_internal/src/file.rs index b10256d532..0406ca30f9 100644 --- a/crates/compiler/load_internal/src/file.rs +++ b/crates/compiler/load_internal/src/file.rs @@ -4766,6 +4766,8 @@ fn build_pending_specializations<'a>( // mark this symbol as a top-level thunk before any other work on the procs module_thunks.push(symbol); + let expr_var = Variable::EMPTY_RECORD; + let is_host_exposed = true; // If this is an exposed symbol, we need to @@ -4805,6 +4807,8 @@ fn build_pending_specializations<'a>( ); } + let body = roc_can::expr::convert_toplevel_expect(body); + let proc = PartialProc { annotation: expr_var, // This is a 0-arity thunk, so it has no arguments.