diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 0b5856911c..327606d9ee 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -44,6 +44,22 @@ macro_rules! macro_magic { /// delegates to the compiler-internal List.getUnsafe function to do the actual /// lookup (if the bounds check passed). That internal function is hardcoded in code gen, /// which works fine because it doesn't involve any open tag unions. + +/// Does a builtin depend on any other builtins? +/// +/// NOTE: you are supposed to give all symbols that are relied on, +/// even those that are relied on transitively! +pub fn builtin_dependencies(symbol: Symbol) -> &'static [Symbol] { + match symbol { + // Symbol::LIST_SORT_ASC => &[Symbol::LIST_SORT_WITH, Symbol::NUM_COMPARE], + Symbol::LIST_PRODUCT => &[Symbol::LIST_WALK, Symbol::NUM_MUL], + Symbol::LIST_SUM => &[Symbol::LIST_WALK, Symbol::NUM_ADD], + Symbol::LIST_JOIN_MAP => &[Symbol::LIST_WALK, Symbol::LIST_CONCAT], + _ => &[], + } +} + +/// Implementation for a builtin pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option { debug_assert!(symbol.is_builtin()); @@ -3273,15 +3289,22 @@ fn list_sum(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); let closure_var = var_store.fresh(); - let body = RunLowLevel { - op: LowLevel::ListWalk, - args: vec![ - (list_var, Var(Symbol::ARG_1)), - (num_var, num(var_store.fresh(), 0)), - (closure_var, list_sum_add(num_var, var_store)), - ], + let function = ( + var_store.fresh(), + Loc::at_zero(Expr::Var(Symbol::LIST_WALK)), + var_store.fresh(), ret_var, - }; + ); + + let body = Expr::Call( + Box::new(function), + vec![ + (list_var, Loc::at_zero(Var(Symbol::ARG_1))), + (num_var, Loc::at_zero(num(var_store.fresh(), 0))), + (closure_var, Loc::at_zero(Var(Symbol::NUM_ADD))), + ], + CalledVia::Space, + ); defn( symbol, @@ -3292,60 +3315,34 @@ fn list_sum(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } -fn list_sum_add(num_var: Variable, var_store: &mut VarStore) -> Expr { - let body = RunLowLevel { - op: LowLevel::NumAdd, - args: vec![(num_var, Var(Symbol::ARG_3)), (num_var, Var(Symbol::ARG_4))], - ret_var: num_var, - }; - - defn_help( - Symbol::LIST_SUM_ADD, - vec![(num_var, Symbol::ARG_3), (num_var, Symbol::ARG_4)], - var_store, - body, - num_var, - ) -} - /// List.product : List (Num a) -> Num a fn list_product(symbol: Symbol, var_store: &mut VarStore) -> Def { let num_var = var_store.fresh(); - let ret_var = num_var; let list_var = var_store.fresh(); let closure_var = var_store.fresh(); - let body = RunLowLevel { - op: LowLevel::ListWalk, - args: vec![ - (list_var, Var(Symbol::ARG_1)), - (num_var, num(var_store.fresh(), 1)), - (closure_var, list_product_mul(num_var, var_store)), + let function = ( + var_store.fresh(), + Loc::at_zero(Expr::Var(Symbol::LIST_WALK)), + var_store.fresh(), + num_var, + ); + + let body = Expr::Call( + Box::new(function), + vec![ + (list_var, Loc::at_zero(Var(Symbol::ARG_1))), + (num_var, Loc::at_zero(num(var_store.fresh(), 1))), + (closure_var, Loc::at_zero(Var(Symbol::NUM_MUL))), ], - ret_var, - }; + CalledVia::Space, + ); defn( symbol, vec![(list_var, Symbol::ARG_1)], var_store, body, - ret_var, - ) -} - -fn list_product_mul(num_var: Variable, var_store: &mut VarStore) -> Expr { - let body = RunLowLevel { - op: LowLevel::NumMul, - args: vec![(num_var, Var(Symbol::ARG_3)), (num_var, Var(Symbol::ARG_4))], - ret_var: num_var, - }; - - defn_help( - Symbol::LIST_PRODUCT_MUL, - vec![(num_var, Symbol::ARG_3), (num_var, Symbol::ARG_4)], - var_store, - body, num_var, ) } diff --git a/compiler/can/src/module.rs b/compiler/can/src/module.rs index 07a19cc654..1f57cc8734 100644 --- a/compiler/can/src/module.rs +++ b/compiler/can/src/module.rs @@ -181,6 +181,17 @@ where references.insert(*symbol); } + // add any builtins used by other builtins + let transitive_builtins: Vec = references + .iter() + .filter(|s| s.is_builtin()) + .map(|s| crate::builtins::builtin_dependencies(*s)) + .flatten() + .copied() + .collect(); + + references.extend(transitive_builtins); + // NOTE previously we inserted builtin defs into the list of defs here // this is now done later, in file.rs. diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 7d3472d224..2110083ec4 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -1082,36 +1082,34 @@ define_builtins! { 24 LIST_MAP2: "map2" 25 LIST_MAP3: "map3" 26 LIST_PRODUCT: "product" - 27 LIST_SUM_ADD: "#sumadd" - 28 LIST_PRODUCT_MUL: "#productmul" - 29 LIST_WALK_UNTIL: "walkUntil" - 30 LIST_RANGE: "range" - 31 LIST_SORT_WITH: "sortWith" - 32 LIST_DROP: "drop" - 33 LIST_SWAP: "swap" - 34 LIST_DROP_AT: "dropAt" - 35 LIST_DROP_LAST: "dropLast" - 36 LIST_MIN: "min" - 37 LIST_MIN_LT: "#minlt" - 38 LIST_MAX: "max" - 39 LIST_MAX_GT: "#maxGt" - 40 LIST_MAP4: "map4" - 41 LIST_DROP_FIRST: "dropFirst" - 42 LIST_JOIN_MAP: "joinMap" - 43 LIST_JOIN_MAP_CONCAT: "#joinMapConcat" - 44 LIST_ANY: "any" - 45 LIST_TAKE_FIRST: "takeFirst" - 46 LIST_TAKE_LAST: "takeLast" - 47 LIST_FIND: "find" - 48 LIST_FIND_RESULT: "#find_result" // symbol used in the definition of List.find - 49 LIST_SUBLIST: "sublist" - 50 LIST_INTERSPERSE: "intersperse" - 51 LIST_INTERSPERSE_CLOS: "#intersperseClos" - 52 LIST_SPLIT: "split" - 53 LIST_SPLIT_CLOS: "#splitClos" - 54 LIST_ALL: "all" - 55 LIST_DROP_IF: "dropIf" - 56 LIST_DROP_IF_PREDICATE: "#dropIfPred" + 27 LIST_WALK_UNTIL: "walkUntil" + 28 LIST_RANGE: "range" + 29 LIST_SORT_WITH: "sortWith" + 30 LIST_DROP: "drop" + 31 LIST_SWAP: "swap" + 32 LIST_DROP_AT: "dropAt" + 33 LIST_DROP_LAST: "dropLast" + 34 LIST_MIN: "min" + 35 LIST_MIN_LT: "#minlt" + 36 LIST_MAX: "max" + 37 LIST_MAX_GT: "#maxGt" + 38 LIST_MAP4: "map4" + 39 LIST_DROP_FIRST: "dropFirst" + 40 LIST_JOIN_MAP: "joinMap" + 41 LIST_JOIN_MAP_CONCAT: "#joinMapConcat" + 42 LIST_ANY: "any" + 43 LIST_TAKE_FIRST: "takeFirst" + 44 LIST_TAKE_LAST: "takeLast" + 45 LIST_FIND: "find" + 46 LIST_FIND_RESULT: "#find_result" // symbol used in the definition of List.find + 47 LIST_SUBLIST: "sublist" + 48 LIST_INTERSPERSE: "intersperse" + 49 LIST_INTERSPERSE_CLOS: "#intersperseClos" + 50 LIST_SPLIT: "split" + 51 LIST_SPLIT_CLOS: "#splitClos" + 52 LIST_ALL: "all" + 53 LIST_DROP_IF: "dropIf" + 54 LIST_DROP_IF_PREDICATE: "#dropIfPred" } 5 RESULT: "Result" => { 0 RESULT_RESULT: "Result" imported // the Result.Result type alias