diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 5b93c6510f..711bb51fef 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -1,5 +1,5 @@ use crate::def::Def; -use crate::expr::Expr::*; +use crate::expr::{ClosureData, Expr::*}; use crate::expr::{Expr, Recursive, WhenBranch}; use crate::pattern::Pattern; use roc_collections::all::SendMap; @@ -2889,7 +2889,7 @@ fn set_walk(symbol: Symbol, var_store: &mut VarStore) -> Def { CalledVia::Space, ); - let wrapper = Closure { + let wrapper = Closure(ClosureData { function_type: wrapper_var, closure_type: var_store.fresh(), closure_ext_var: var_store.fresh(), @@ -2903,7 +2903,7 @@ fn set_walk(symbol: Symbol, var_store: &mut VarStore) -> Def { (Variable::EMPTY_RECORD, no_region(Pattern::Underscore)), ], loc_body: Box::new(no_region(call_func)), - }; + }); let body = RunLowLevel { op: LowLevel::DictWalk, @@ -3918,7 +3918,7 @@ fn defn_help( .map(|(var, symbol)| (var, no_region(Identifier(symbol)))) .collect(); - Closure { + Closure(ClosureData { function_type: var_store.fresh(), closure_type: var_store.fresh(), closure_ext_var: var_store.fresh(), @@ -3928,7 +3928,7 @@ fn defn_help( recursive: Recursive::NotRecursive, arguments: closure_args, loc_body: Box::new(no_region(body)), - } + }) } #[inline(always)] diff --git a/compiler/can/src/def.rs b/compiler/can/src/def.rs index e5e3414048..a44e83efe0 100644 --- a/compiler/can/src/def.rs +++ b/compiler/can/src/def.rs @@ -1,6 +1,7 @@ use crate::annotation::canonicalize_annotation; use crate::annotation::IntroducedVariables; use crate::env::Env; +use crate::expr::ClosureData; use crate::expr::Expr::{self, *}; use crate::expr::{ canonicalize_expr, local_successors, references_from_call, references_from_local, Output, @@ -670,10 +671,10 @@ fn group_to_declaration( let mut new_def = can_def.clone(); // Determine recursivity of closures that are not tail-recursive - if let Closure { + if let Closure(ClosureData { recursive: recursive @ Recursive::NotRecursive, .. - } = &mut new_def.loc_expr.value + }) = &mut new_def.loc_expr.value { *recursive = closure_recursivity(*symbol, closures); } @@ -698,10 +699,10 @@ fn group_to_declaration( let mut new_def = can_def.clone(); // Determine recursivity of closures that are not tail-recursive - if let Closure { + if let Closure(ClosureData { recursive: recursive @ Recursive::NotRecursive, .. - } = &mut new_def.loc_expr.value + }) = &mut new_def.loc_expr.value { *recursive = closure_recursivity(symbol, closures); } @@ -838,7 +839,7 @@ fn canonicalize_pending_def<'a>( }; Located { - value: Closure { + value: Closure(ClosureData { function_type: var_store.fresh(), closure_type: var_store.fresh(), closure_ext_var: var_store.fresh(), @@ -848,7 +849,7 @@ fn canonicalize_pending_def<'a>( recursive: Recursive::NotRecursive, arguments: underscores, loc_body: Box::new(body_expr), - }, + }), region: loc_ann.region, } }; @@ -1001,7 +1002,7 @@ fn canonicalize_pending_def<'a>( if let ( &ast::Pattern::Identifier(_name), &Pattern::Identifier(ref defined_symbol), - &Closure { + &Closure(ClosureData { function_type, closure_type, closure_ext_var, @@ -1011,7 +1012,7 @@ fn canonicalize_pending_def<'a>( loc_body: ref body, ref captured_symbols, .. - }, + }), ) = ( &loc_pattern.value, &loc_can_pattern.value, @@ -1049,7 +1050,7 @@ fn canonicalize_pending_def<'a>( }); // renamed_closure_def = Some(&defined_symbol); - loc_can_expr.value = Closure { + loc_can_expr.value = Closure(ClosureData { function_type, closure_type, closure_ext_var, @@ -1059,7 +1060,7 @@ fn canonicalize_pending_def<'a>( recursive: is_recursive, arguments: arguments.clone(), loc_body: body.clone(), - }; + }); } // Store the referenced locals in the refs_by_symbol map, so we can later figure out @@ -1144,7 +1145,7 @@ fn canonicalize_pending_def<'a>( if let ( &ast::Pattern::Identifier(_name), &Pattern::Identifier(ref defined_symbol), - &Closure { + &Closure(ClosureData { function_type, closure_type, closure_ext_var, @@ -1154,7 +1155,7 @@ fn canonicalize_pending_def<'a>( loc_body: ref body, ref captured_symbols, .. - }, + }), ) = ( &loc_pattern.value, &loc_can_pattern.value, @@ -1191,7 +1192,7 @@ fn canonicalize_pending_def<'a>( refs.lookups = refs.lookups.without(defined_symbol); }); - loc_can_expr.value = Closure { + loc_can_expr.value = Closure(ClosureData { function_type, closure_type, closure_ext_var, @@ -1201,7 +1202,7 @@ fn canonicalize_pending_def<'a>( recursive: is_recursive, arguments: arguments.clone(), loc_body: body.clone(), - }; + }); } // Store the referenced locals in the refs_by_symbol map, so we can later figure out diff --git a/compiler/can/src/expr.rs b/compiler/can/src/expr.rs index 5dd8903993..79d762560e 100644 --- a/compiler/can/src/expr.rs +++ b/compiler/can/src/expr.rs @@ -102,17 +102,7 @@ pub enum Expr { ret_var: Variable, }, - Closure { - function_type: Variable, - closure_type: Variable, - closure_ext_var: Variable, - return_type: Variable, - name: Symbol, - captured_symbols: Vec<(Symbol, Variable)>, - recursive: Recursive, - arguments: Vec<(Variable, Located)>, - loc_body: Box>, - }, + Closure(ClosureData), // Product Types Record { @@ -173,6 +163,18 @@ pub enum Expr { // Compiles, but will crash if reached RuntimeError(RuntimeError), } +#[derive(Clone, Debug, PartialEq)] +pub struct ClosureData { + pub function_type: Variable, + pub closure_type: Variable, + pub closure_ext_var: Variable, + pub return_type: Variable, + pub name: Symbol, + pub captured_symbols: Vec<(Symbol, Variable)>, + pub recursive: Recursive, + pub arguments: Vec<(Variable, Located)>, + pub loc_body: Box>, +} #[derive(Clone, Debug, PartialEq)] pub struct Field { @@ -572,7 +574,7 @@ pub fn canonicalize_expr<'a>( } ( - Closure { + Closure(ClosureData { function_type: var_store.fresh(), closure_type: var_store.fresh(), closure_ext_var: var_store.fresh(), @@ -582,7 +584,7 @@ pub fn canonicalize_expr<'a>( recursive: Recursive::NotRecursive, arguments: can_args, loc_body: Box::new(loc_body_expr), - }, + }), output, ) } @@ -1403,7 +1405,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) -> LetNonRec(Box::new(def), Box::new(loc_expr), var) } - Closure { + Closure(ClosureData { function_type, closure_type, closure_ext_var, @@ -1413,14 +1415,14 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) -> captured_symbols, arguments, loc_body, - } => { + }) => { let loc_expr = *loc_body; let loc_expr = Located { value: inline_calls(var_store, scope, loc_expr.value), region: loc_expr.region, }; - Closure { + Closure(ClosureData { function_type, closure_type, closure_ext_var, @@ -1430,7 +1432,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) -> captured_symbols, arguments, loc_body: Box::new(loc_expr), - } + }) } Record { record_var, fields } => { @@ -1492,12 +1494,12 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) -> loc_expr: Located { value: - Closure { + Closure(ClosureData { recursive, arguments: params, loc_body: boxed_body, .. - }, + }), .. }, .. diff --git a/compiler/can/src/module.rs b/compiler/can/src/module.rs index 771f73611d..f8c6928e56 100644 --- a/compiler/can/src/module.rs +++ b/compiler/can/src/module.rs @@ -1,6 +1,6 @@ use crate::def::{canonicalize_defs, sort_can_defs, Declaration, Def}; use crate::env::Env; -use crate::expr::{Expr, Output}; +use crate::expr::{ClosureData, Expr, Output}; use crate::operator::desugar_def; use crate::pattern::Pattern; use crate::scope::Scope; @@ -416,13 +416,13 @@ fn fix_values_captured_in_closure_expr( fix_values_captured_in_closure_expr(&mut loc_expr.value, no_capture_symbols); } - Closure { + Closure(ClosureData { captured_symbols, name, arguments, loc_body, .. - } => { + }) => { captured_symbols.retain(|(s, _)| !no_capture_symbols.contains(s)); captured_symbols.retain(|(s, _)| s != name); diff --git a/compiler/constrain/src/expr.rs b/compiler/constrain/src/expr.rs index 4e920147d0..11d8c4cabe 100644 --- a/compiler/constrain/src/expr.rs +++ b/compiler/constrain/src/expr.rs @@ -7,7 +7,7 @@ use roc_can::def::{Declaration, Def}; use roc_can::expected::Expected::{self, *}; use roc_can::expected::PExpected; use roc_can::expr::Expr::{self, *}; -use roc_can::expr::{Field, WhenBranch}; +use roc_can::expr::{ClosureData, Field, WhenBranch}; use roc_can::pattern::Pattern; use roc_collections::all::{ImMap, Index, MutSet, SendMap}; use roc_module::ident::{Lowercase, TagName}; @@ -333,7 +333,7 @@ pub fn constrain_expr( // make lookup constraint to lookup this symbol's type in the environment Lookup(*symbol, expected, region) } - Closure { + Closure(ClosureData { function_type: fn_var, closure_type: closure_var, closure_ext_var, @@ -343,7 +343,7 @@ pub fn constrain_expr( captured_symbols, name, .. - } => { + }) => { // NOTE defs are treated somewhere else! let loc_body_expr = &**boxed; @@ -1203,7 +1203,7 @@ fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint { // instead of the more generic "something is wrong with the body of `f`" match (&def.loc_expr.value, &signature) { ( - Closure { + Closure(ClosureData { function_type: fn_var, closure_type: closure_var, closure_ext_var, @@ -1213,7 +1213,7 @@ fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint { loc_body, name, .. - }, + }), Type::Function(arg_types, signature_closure_type, ret_type), ) => { // NOTE if we ever have problems with the closure, the ignored `_closure_type` @@ -1561,7 +1561,7 @@ pub fn rec_defs_help( // instead of the more generic "something is wrong with the body of `f`" match (&def.loc_expr.value, &signature) { ( - Closure { + Closure(ClosureData { function_type: fn_var, closure_type: closure_var, closure_ext_var, @@ -1571,7 +1571,7 @@ pub fn rec_defs_help( loc_body, name, .. - }, + }), Type::Function(arg_types, _closure_type, ret_type), ) => { // NOTE if we ever have trouble with closure type unification, the ignored diff --git a/compiler/load/src/effect_module.rs b/compiler/load/src/effect_module.rs index f6081e6e21..eeea64d7a1 100644 --- a/compiler/load/src/effect_module.rs +++ b/compiler/load/src/effect_module.rs @@ -1,7 +1,7 @@ use roc_can::annotation::IntroducedVariables; use roc_can::def::{Declaration, Def}; use roc_can::env::Env; -use roc_can::expr::{Expr, Recursive}; +use roc_can::expr::{ClosureData, Expr, Recursive}; use roc_can::pattern::Pattern; use roc_can::scope::Scope; use roc_collections::all::{MutSet, SendMap}; @@ -117,7 +117,7 @@ fn build_effect_always( let body = Expr::Var(value_symbol); - Expr::Closure { + Expr::Closure(ClosureData { function_type: var_store.fresh(), closure_type: var_store.fresh(), closure_ext_var: var_store.fresh(), @@ -127,7 +127,7 @@ fn build_effect_always( recursive: Recursive::NotRecursive, arguments, loc_body: Box::new(Located::at_zero(body)), - } + }) }; // \value -> @Effect \{} -> value @@ -146,7 +146,7 @@ fn build_effect_always( )]; let function_var = var_store.fresh(); - let closure = Expr::Closure { + let closure = Expr::Closure(ClosureData { function_type: function_var, closure_type: var_store.fresh(), closure_ext_var: var_store.fresh(), @@ -156,7 +156,7 @@ fn build_effect_always( recursive: Recursive::NotRecursive, arguments, loc_body: Box::new(Located::at_zero(body)), - }; + }); (function_var, closure) }; @@ -295,7 +295,7 @@ fn build_effect_map( Located::at_zero(empty_record_pattern(var_store)), )]; - Expr::Closure { + Expr::Closure(ClosureData { function_type: var_store.fresh(), closure_type: var_store.fresh(), closure_ext_var: var_store.fresh(), @@ -308,7 +308,7 @@ fn build_effect_map( recursive: Recursive::NotRecursive, arguments, loc_body: Box::new(Located::at_zero(mapper_call)), - } + }) }; let arguments = vec![ @@ -339,7 +339,7 @@ fn build_effect_map( }; let function_var = var_store.fresh(); - let map_closure = Expr::Closure { + let map_closure = Expr::Closure(ClosureData { function_type: function_var, closure_type: var_store.fresh(), closure_ext_var: var_store.fresh(), @@ -349,7 +349,7 @@ fn build_effect_map( recursive: Recursive::NotRecursive, arguments, loc_body: Box::new(Located::at_zero(body)), - }; + }); let mut introduced_variables = IntroducedVariables::default(); @@ -509,7 +509,7 @@ fn build_effect_after( ]; let function_var = var_store.fresh(); - let after_closure = Expr::Closure { + let after_closure = Expr::Closure(ClosureData { function_type: function_var, closure_type: var_store.fresh(), closure_ext_var: var_store.fresh(), @@ -519,7 +519,7 @@ fn build_effect_after( recursive: Recursive::NotRecursive, arguments, loc_body: Box::new(Located::at_zero(to_effect_call)), - }; + }); let mut introduced_variables = IntroducedVariables::default(); @@ -653,7 +653,7 @@ pub fn build_host_exposed_def( .unwrap() }; - let effect_closure = Expr::Closure { + let effect_closure = Expr::Closure(ClosureData { function_type: var_store.fresh(), closure_type: var_store.fresh(), closure_ext_var: var_store.fresh(), @@ -666,7 +666,7 @@ pub fn build_host_exposed_def( Located::at_zero(empty_record_pattern(var_store)), )], loc_body: Box::new(Located::at_zero(low_level_call)), - }; + }); let body = Expr::Tag { variant_var: var_store.fresh(), @@ -675,7 +675,7 @@ pub fn build_host_exposed_def( arguments: vec![(var_store.fresh(), Located::at_zero(effect_closure))], }; - Expr::Closure { + Expr::Closure(ClosureData { function_type: var_store.fresh(), closure_type: var_store.fresh(), closure_ext_var: var_store.fresh(), @@ -685,7 +685,7 @@ pub fn build_host_exposed_def( recursive: Recursive::NotRecursive, arguments, loc_body: Box::new(Located::at_zero(body)), - } + }) } _ => { // not a function @@ -717,7 +717,7 @@ pub fn build_host_exposed_def( destructs: vec![], }; - let effect_closure = Expr::Closure { + let effect_closure = Expr::Closure(ClosureData { function_type: var_store.fresh(), closure_type: var_store.fresh(), closure_ext_var: var_store.fresh(), @@ -727,7 +727,7 @@ pub fn build_host_exposed_def( recursive: Recursive::NotRecursive, arguments: vec![(var_store.fresh(), Located::at_zero(empty_record_pattern))], loc_body: Box::new(Located::at_zero(low_level_call)), - }; + }); Expr::Tag { variant_var: var_store.fresh(), diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index fdfb078fb3..6f54523532 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -4129,6 +4129,7 @@ fn add_def_to_module<'a>( exposed_to_host: &MutMap, is_recursive: bool, ) { + use roc_can::expr::ClosureData; use roc_can::expr::Expr::*; use roc_can::pattern::Pattern::*; @@ -4137,14 +4138,14 @@ fn add_def_to_module<'a>( let is_exposed = exposed_to_host.contains_key(&symbol); match def.loc_expr.value { - Closure { + Closure(ClosureData { function_type: annotation, return_type: ret_var, arguments: loc_args, loc_body, captured_symbols, .. - } => { + }) => { // this is a top-level definition, it should not capture anything debug_assert!(captured_symbols.is_empty()); diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index ceb648644c..27319ace28 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -9,6 +9,7 @@ use crate::layout::{ use bumpalo::collections::Vec; use bumpalo::Bump; use hashbrown::hash_map::Entry; +use roc_can::expr::ClosureData; use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap}; use roc_module::ident::{ForeignSymbol, Lowercase, TagName}; use roc_module::low_level::LowLevel; @@ -2910,7 +2911,7 @@ pub fn with_hole<'a>( } LetNonRec(def, cont, _) => { if let roc_can::pattern::Pattern::Identifier(symbol) = &def.loc_pattern.value { - if let Closure { + if let Closure(ClosureData { function_type, return_type, recursive, @@ -2918,7 +2919,7 @@ pub fn with_hole<'a>( loc_body: boxed_body, captured_symbols, .. - } = def.loc_expr.value + }) = def.loc_expr.value { // Extract Procs, but discard the resulting Expr::Load. // That Load looks up the pointer, which we won't use here! @@ -3086,14 +3087,14 @@ pub fn with_hole<'a>( // because Roc is strict, only functions can be recursive! for def in defs.into_iter() { if let roc_can::pattern::Pattern::Identifier(symbol) = &def.loc_pattern.value { - if let Closure { + if let Closure(ClosureData { function_type, return_type, recursive, arguments, loc_body: boxed_body, .. - } = def.loc_expr.value + }) = def.loc_expr.value { // Extract Procs, but discard the resulting Expr::Load. // That Load looks up the pointer, which we won't use here! @@ -3811,7 +3812,7 @@ pub fn with_hole<'a>( } } - Closure { + Closure(ClosureData { function_type, return_type, name, @@ -3819,7 +3820,7 @@ pub fn with_hole<'a>( captured_symbols, loc_body: boxed_body, .. - } => { + }) => { let loc_body = *boxed_body; let raw = layout_cache.raw_from_var(env.arena, function_type, env.subs); @@ -4803,14 +4804,14 @@ pub fn from_can<'a>( // Now that we know for sure it's a closure, get an owned // version of these variant args so we can use them properly. match def.loc_expr.value { - Closure { + Closure(ClosureData { function_type, return_type, recursive, arguments, loc_body: boxed_body, .. - } => { + }) => { // Extract Procs, but discard the resulting Expr::Load. // That Load looks up the pointer, which we won't use here! @@ -4844,11 +4845,11 @@ pub fn from_can<'a>( } LetNonRec(def, cont, outer_annotation) => { if let roc_can::pattern::Pattern::Identifier(symbol) = &def.loc_pattern.value { - if let Closure { .. } = &def.loc_expr.value { + if let Closure(_) = &def.loc_expr.value { // Now that we know for sure it's a closure, get an owned // version of these variant args so we can use them properly. match def.loc_expr.value { - Closure { + Closure(ClosureData { function_type, return_type, closure_type, @@ -4858,7 +4859,7 @@ pub fn from_can<'a>( loc_body: boxed_body, captured_symbols, .. - } => { + }) => { if true || !procs.partial_procs.contains_key(*symbol) { let loc_body = *boxed_body;