Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

Add inlining tests on the JavaScript target

+529 -2
+6 -2
compiler-core/src/javascript/tests.rs
··· 2 2 analyse::TargetSupport, 3 3 build::{Origin, Target}, 4 4 config::PackageConfig, 5 + inline, 5 6 javascript::*, 6 7 uid::UniqueIdGenerator, 7 8 warning::{TypeWarningEmitter, WarningEmitter}, ··· 21 22 mod externals; 22 23 mod functions; 23 24 mod generics; 25 + mod inlining; 24 26 mod lists; 25 27 mod modules; 26 28 mod numbers; ··· 171 173 let mut config = PackageConfig::default(); 172 174 config.name = "thepackage".into(); 173 175 174 - crate::analyse::ModuleAnalyzerConstructor::<()> { 176 + let module = crate::analyse::ModuleAnalyzerConstructor::<()> { 175 177 target: Target::JavaScript, 176 178 ids: &ids, 177 179 origin: Origin::Src, ··· 182 184 package_config: &config, 183 185 } 184 186 .infer_module(ast, line_numbers, "src/module.gleam".into()) 185 - .expect("should successfully infer") 187 + .expect("should successfully infer"); 188 + 189 + inline::module(module, &modules) 186 190 } 187 191 188 192 pub fn compile_js(src: &str, deps: Vec<(&str, &str, &str)>) -> String {
+206
compiler-core/src/javascript/tests/inlining.rs
··· 1 + use crate::assert_js; 2 + 3 + const BOOL_MODULE: &str = " 4 + pub fn guard( 5 + when condition: Bool, 6 + return value: a, 7 + otherwise callback: fn() -> a, 8 + ) -> a { 9 + case condition { 10 + True -> value 11 + False -> callback() 12 + } 13 + } 14 + 15 + pub fn lazy_guard( 16 + when condition: Bool, 17 + return consequence: fn() -> a, 18 + otherwise alternative: fn() -> a, 19 + ) -> a { 20 + case condition { 21 + True -> consequence() 22 + False -> alternative() 23 + } 24 + } 25 + "; 26 + 27 + const RESULT_MODULE: &str = " 28 + pub fn try(result: Result(a, e), apply f: fn(a) -> Result(b, e)) -> Result(b, e) { 29 + case result { 30 + Ok(value) -> f(value) 31 + Error(error) -> Error(error) 32 + } 33 + } 34 + 35 + pub fn then(result: Result(a, e), apply f: fn(a) -> Result(b, e)) -> Result(b, e) { 36 + try(result, f) 37 + } 38 + 39 + pub fn map(over result: Result(a, e), with f: fn(a) -> b) -> Result(b, e) { 40 + case result { 41 + Ok(value) -> Ok(f(value)) 42 + Error(error) -> Error(error) 43 + } 44 + } 45 + "; 46 + 47 + #[test] 48 + fn inline_higher_order_function() { 49 + assert_js!( 50 + ("gleam_stdlib", "gleam/result", RESULT_MODULE), 51 + " 52 + import gleam/result 53 + 54 + pub fn main() { 55 + result.map(over: Ok(10), apply: double) 56 + } 57 + 58 + fn double(x) { x + x } 59 + " 60 + ); 61 + } 62 + 63 + #[test] 64 + fn inline_higher_order_function_with_capture() { 65 + assert_js!( 66 + ("gleam_stdlib", "gleam/result", RESULT_MODULE), 67 + " 68 + import gleam/result 69 + 70 + pub fn main() { 71 + result.try(Ok(10), divide(_, 2)) 72 + } 73 + 74 + fn divide(a: Int, b: Int) -> Result(Int, Nil) { 75 + case a % b { 76 + 0 -> Ok(a / b) 77 + _ -> Error(Nil) 78 + } 79 + } 80 + " 81 + ); 82 + } 83 + 84 + #[test] 85 + fn inline_higher_order_function_anonymous() { 86 + assert_js!( 87 + ("gleam_stdlib", "gleam/result", RESULT_MODULE), 88 + " 89 + import gleam/result 90 + 91 + pub fn main() { 92 + result.try(Ok(10), fn(value) { 93 + Ok({ value + 2 } * 4) 94 + }) 95 + } 96 + " 97 + ); 98 + } 99 + 100 + #[test] 101 + fn inline_function_which_calls_other_function() { 102 + // `result.then` calls `result.try`, meaning this must be inlined twice to 103 + // achieve the desired result. 104 + assert_js!( 105 + ("gleam_stdlib", "gleam/result", RESULT_MODULE), 106 + " 107 + import gleam/result 108 + 109 + pub fn main() { 110 + result.then(Ok(10), Error) 111 + } 112 + " 113 + ); 114 + } 115 + 116 + #[test] 117 + fn inline_function_with_use() { 118 + assert_js!( 119 + ("gleam_stdlib", "gleam/bool", BOOL_MODULE), 120 + " 121 + import gleam/bool 122 + 123 + pub fn divide(a, b) { 124 + use <- bool.guard(when: b == 0, return: 0) 125 + a / b 126 + } 127 + " 128 + ); 129 + } 130 + 131 + #[test] 132 + fn inline_function_with_use_and_anonymous() { 133 + assert_js!( 134 + ("gleam_stdlib", "gleam/bool", BOOL_MODULE), 135 + r#" 136 + import gleam/bool 137 + 138 + pub fn divide(a, b) { 139 + use <- bool.lazy_guard(b == 0, fn() { panic as "Cannot divide by 0" }) 140 + a / b 141 + } 142 + "# 143 + ); 144 + } 145 + 146 + #[test] 147 + fn inline_function_with_use_becomes_tail_recursive() { 148 + assert_js!( 149 + ("gleam_stdlib", "gleam/bool", BOOL_MODULE), 150 + " 151 + import gleam/bool 152 + 153 + pub fn count(from: Int, to: Int) -> Int { 154 + use <- bool.guard(when: from >= to, return: from) 155 + echo from 156 + count(from + 1, to) 157 + } 158 + " 159 + ); 160 + } 161 + 162 + #[test] 163 + fn do_not_inline_parameters_used_more_than_once() { 164 + // We just use `bool.guard` as the name here because it will be inlined 165 + assert_js!( 166 + ( 167 + "gleam_stdlib", 168 + "gleam/bool", 169 + " 170 + pub fn guard(something) { 171 + case something { 172 + True -> something 173 + False -> something 174 + } 175 + } 176 + " 177 + ), 178 + " 179 + import gleam/bool 180 + 181 + pub fn main() { 182 + bool.guard(True) 183 + } 184 + " 185 + ); 186 + } 187 + 188 + #[test] 189 + fn do_not_inline_parameters_that_have_side_effects() { 190 + assert_js!( 191 + ("gleam_stdlib", "gleam/result", RESULT_MODULE), 192 + r#" 193 + import gleam/result 194 + 195 + pub fn main() { 196 + result.map(Ok(10), do_side_effects()) 197 + } 198 + 199 + fn do_side_effects() { 200 + let function = fn(x) { x + 1 } 201 + panic as "Side effects" 202 + function 203 + } 204 + "# 205 + ); 206 + }
+52
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__do_not_inline_parameters_that_have_side_effects.snap
··· 1 + --- 2 + source: compiler-core/src/javascript/tests/inlining.rs 3 + expression: "\nimport gleam/result\n\npub fn main() {\n result.map(Ok(10), do_side_effects())\n}\n\nfn do_side_effects() {\n let function = fn(x) { x + 1 }\n panic as \"Side effects\"\n function\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + import gleam/result 8 + 9 + pub fn main() { 10 + result.map(Ok(10), do_side_effects()) 11 + } 12 + 13 + fn do_side_effects() { 14 + let function = fn(x) { x + 1 } 15 + panic as "Side effects" 16 + function 17 + } 18 + 19 + 20 + ----- COMPILED JAVASCRIPT 21 + import * as $result from "../../gleam_stdlib/gleam/result.mjs"; 22 + import { Ok, makeError } from "../gleam.mjs"; 23 + 24 + const FILEPATH = "src/module.gleam"; 25 + 26 + function do_side_effects() { 27 + let function$ = (x) => { return x + 1; }; 28 + throw makeError( 29 + "panic", 30 + FILEPATH, 31 + "my/mod", 32 + 10, 33 + "do_side_effects", 34 + "Side effects", 35 + {} 36 + ) 37 + return function$; 38 + } 39 + 40 + export function main() { 41 + { 42 + let f = do_side_effects(); 43 + let $ = new Ok(10); 44 + if ($ instanceof Ok) { 45 + let value = $[0]; 46 + return new Ok(f(value)); 47 + } else { 48 + let error = $[0]; 49 + return new Error(error); 50 + } 51 + } 52 + }
+26
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__do_not_inline_parameters_used_more_than_once.snap
··· 1 + --- 2 + source: compiler-core/src/javascript/tests/inlining.rs 3 + expression: "\nimport gleam/bool\n\npub fn main() {\n bool.guard(True)\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + import gleam/bool 8 + 9 + pub fn main() { 10 + bool.guard(True) 11 + } 12 + 13 + 14 + ----- COMPILED JAVASCRIPT 15 + import * as $bool from "../../gleam_stdlib/gleam/bool.mjs"; 16 + 17 + export function main() { 18 + { 19 + let something = true; 20 + if (something) { 21 + return something; 22 + } else { 23 + return something; 24 + } 25 + } 26 + }
+27
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_function_which_calls_other_function.snap
··· 1 + --- 2 + source: compiler-core/src/javascript/tests/inlining.rs 3 + expression: "\nimport gleam/result\n\npub fn main() {\n result.then(Ok(10), Error)\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + import gleam/result 8 + 9 + pub fn main() { 10 + result.then(Ok(10), Error) 11 + } 12 + 13 + 14 + ----- COMPILED JAVASCRIPT 15 + import * as $result from "../../gleam_stdlib/gleam/result.mjs"; 16 + import { Ok, Error } from "../gleam.mjs"; 17 + 18 + export function main() { 19 + let $ = new Ok(10); 20 + if ($ instanceof Ok) { 21 + let value = $[0]; 22 + return new Error(value); 23 + } else { 24 + let error = $[0]; 25 + return new Error(error); 26 + } 27 + }
+26
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_function_with_use.snap
··· 1 + --- 2 + source: compiler-core/src/javascript/tests/inlining.rs 3 + expression: "\nimport gleam/bool\n\npub fn divide(a, b) {\n use <- bool.guard(when: b == 0, return: 0)\n a / b\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + import gleam/bool 8 + 9 + pub fn divide(a, b) { 10 + use <- bool.guard(when: b == 0, return: 0) 11 + a / b 12 + } 13 + 14 + 15 + ----- COMPILED JAVASCRIPT 16 + import * as $bool from "../../gleam_stdlib/gleam/bool.mjs"; 17 + import { divideInt } from "../gleam.mjs"; 18 + 19 + export function divide(a, b) { 20 + let $ = b === 0; 21 + if ($) { 22 + return 0; 23 + } else { 24 + return divideInt(a, b); 25 + } 26 + }
+36
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_function_with_use_and_anonymous.snap
··· 1 + --- 2 + source: compiler-core/src/javascript/tests/inlining.rs 3 + expression: "\nimport gleam/bool\n\npub fn divide(a, b) {\n use <- bool.lazy_guard(b == 0, fn() { panic as \"Cannot divide by 0\" })\n a / b\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + import gleam/bool 8 + 9 + pub fn divide(a, b) { 10 + use <- bool.lazy_guard(b == 0, fn() { panic as "Cannot divide by 0" }) 11 + a / b 12 + } 13 + 14 + 15 + ----- COMPILED JAVASCRIPT 16 + import * as $bool from "../../gleam_stdlib/gleam/bool.mjs"; 17 + import { makeError, divideInt } from "../gleam.mjs"; 18 + 19 + const FILEPATH = "src/module.gleam"; 20 + 21 + export function divide(a, b) { 22 + let $ = b === 0; 23 + if ($) { 24 + throw makeError( 25 + "panic", 26 + FILEPATH, 27 + "my/mod", 28 + 5, 29 + "divide", 30 + "Cannot divide by 0", 31 + {} 32 + ) 33 + } else { 34 + return divideInt(a, b); 35 + } 36 + }
+43
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_function_with_use_becomes_tail_recursive.snap
··· 1 + --- 2 + source: compiler-core/src/javascript/tests/inlining.rs 3 + expression: "\nimport gleam/bool\n\npub fn count(from: Int, to: Int) -> Int {\n use <- bool.guard(when: from >= to, return: from)\n echo from\n count(from + 1, to)\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + import gleam/bool 8 + 9 + pub fn count(from: Int, to: Int) -> Int { 10 + use <- bool.guard(when: from >= to, return: from) 11 + echo from 12 + count(from + 1, to) 13 + } 14 + 15 + 16 + ----- COMPILED JAVASCRIPT 17 + import * as $stdlib$dict from "../../gleam_stdlib/dict.mjs"; 18 + import * as $bool from "../../gleam_stdlib/gleam/bool.mjs"; 19 + import { 20 + CustomType as $CustomType, 21 + bitArraySlice, 22 + bitArraySliceToInt, 23 + BitArray as $BitArray, 24 + List as $List, 25 + UtfCodepoint as $UtfCodepoint, 26 + } from "../gleam.mjs"; 27 + 28 + export function count(loop$from, loop$to) { 29 + while (true) { 30 + let from = loop$from; 31 + let to = loop$to; 32 + let $ = from >= to; 33 + if ($) { 34 + return from; 35 + } else { 36 + echo(from, "src/module.gleam", 6); 37 + loop$from = from + 1; 38 + loop$to = to; 39 + } 40 + } 41 + } 42 + 43 + // ...omitted code from `templates/echo.mjs`...
+33
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_higher_order_function.snap
··· 1 + --- 2 + source: compiler-core/src/javascript/tests/inlining.rs 3 + expression: "\nimport gleam/result\n\npub fn main() {\n result.map(Ok(10), double)\n}\n\nfn double(x) { x + x }\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + import gleam/result 8 + 9 + pub fn main() { 10 + result.map(Ok(10), double) 11 + } 12 + 13 + fn double(x) { x + x } 14 + 15 + 16 + ----- COMPILED JAVASCRIPT 17 + import * as $result from "../../gleam_stdlib/gleam/result.mjs"; 18 + import { Ok } from "../gleam.mjs"; 19 + 20 + function double(x) { 21 + return x + x; 22 + } 23 + 24 + export function main() { 25 + let $ = new Ok(10); 26 + if ($ instanceof Ok) { 27 + let value = $[0]; 28 + return new Ok(double(value)); 29 + } else { 30 + let error = $[0]; 31 + return new Error(error); 32 + } 33 + }
+30
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_higher_order_function_anonymous.snap
··· 1 + --- 2 + source: compiler-core/src/javascript/tests/inlining.rs 3 + expression: "\nimport gleam/result\n\npub fn main() {\n result.try(Ok(10), fn(value) {\n Ok({ value + 2 } * 4)\n })\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + import gleam/result 8 + 9 + pub fn main() { 10 + result.try(Ok(10), fn(value) { 11 + Ok({ value + 2 } * 4) 12 + }) 13 + } 14 + 15 + 16 + ----- COMPILED JAVASCRIPT 17 + import * as $result from "../../gleam_stdlib/gleam/result.mjs"; 18 + import { Ok } from "../gleam.mjs"; 19 + 20 + export function main() { 21 + let $ = new Ok(10); 22 + if ($ instanceof Ok) { 23 + let value = $[0]; 24 + let value$1 = value; 25 + return new Ok((value$1 + 2) * 4); 26 + } else { 27 + let error = $[0]; 28 + return new Error(error); 29 + } 30 + }
+44
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__inlining__inline_higher_order_function_with_capture.snap
··· 1 + --- 2 + source: compiler-core/src/javascript/tests/inlining.rs 3 + expression: "\nimport gleam/result\n\npub fn main() {\n result.try(Ok(10), divide(_, 2))\n}\n\nfn divide(a: Int, b: Int) -> Result(Int, Nil) {\n case a % b {\n 0 -> Ok(a / b)\n _ -> Error(Nil)\n }\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + import gleam/result 8 + 9 + pub fn main() { 10 + result.try(Ok(10), divide(_, 2)) 11 + } 12 + 13 + fn divide(a: Int, b: Int) -> Result(Int, Nil) { 14 + case a % b { 15 + 0 -> Ok(a / b) 16 + _ -> Error(Nil) 17 + } 18 + } 19 + 20 + 21 + ----- COMPILED JAVASCRIPT 22 + import * as $result from "../../gleam_stdlib/gleam/result.mjs"; 23 + import { Ok, Error, remainderInt, divideInt } from "../gleam.mjs"; 24 + 25 + function divide(a, b) { 26 + let $ = remainderInt(a, b); 27 + if ($ === 0) { 28 + return new Ok(divideInt(a, b)); 29 + } else { 30 + return new Error(undefined); 31 + } 32 + } 33 + 34 + export function main() { 35 + let $ = new Ok(10); 36 + if ($ instanceof Ok) { 37 + let value = $[0]; 38 + let _capture = value; 39 + return divide(_capture, 2); 40 + } else { 41 + let error = $[0]; 42 + return new Error(error); 43 + } 44 + }