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

Configure Feed

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

gleam / compiler-core / src / javascript / tests / inlining.rs
6.7 kB 431 lines
1// SPDX-License-Identifier: Apache-2.0 2// SPDX-FileCopyrightText: 2025 The Gleam contributors 3 4use crate::assert_js; 5 6const BOOL_MODULE: &str = " 7pub fn guard( 8 when condition: Bool, 9 return value: a, 10 otherwise callback: fn() -> a, 11) -> a { 12 case condition { 13 True -> value 14 False -> callback() 15 } 16} 17 18pub fn lazy_guard( 19 when condition: Bool, 20 return consequence: fn() -> a, 21 otherwise alternative: fn() -> a, 22) -> a { 23 case condition { 24 True -> consequence() 25 False -> alternative() 26 } 27} 28"; 29 30const RESULT_MODULE: &str = " 31pub fn try(result: Result(a, e), apply f: fn(a) -> Result(b, e)) -> Result(b, e) { 32 case result { 33 Ok(value) -> f(value) 34 Error(error) -> Error(error) 35 } 36} 37 38pub fn map(over result: Result(a, e), with f: fn(a) -> b) -> Result(b, e) { 39 case result { 40 Ok(value) -> Ok(f(value)) 41 Error(error) -> Error(error) 42 } 43} 44"; 45 46#[test] 47fn inline_higher_order_function() { 48 assert_js!( 49 ("gleam_stdlib", "gleam/result", RESULT_MODULE), 50 " 51import gleam/result 52 53pub fn main() { 54 result.map(over: Ok(10), with: double) 55} 56 57fn double(x) { x + x } 58" 59 ); 60} 61 62#[test] 63fn inline_higher_order_function_with_capture() { 64 assert_js!( 65 ("gleam_stdlib", "gleam/result", RESULT_MODULE), 66 " 67import gleam/result 68 69pub fn main() { 70 result.try(Ok(10), divide(_, 2)) 71} 72 73fn divide(a: Int, b: Int) -> Result(Int, Nil) { 74 case a % b { 75 0 -> Ok(a / b) 76 _ -> Error(Nil) 77 } 78} 79" 80 ); 81} 82 83#[test] 84fn inline_higher_order_function_anonymous() { 85 assert_js!( 86 ("gleam_stdlib", "gleam/result", RESULT_MODULE), 87 " 88import gleam/result 89 90pub fn main() { 91 result.try(Ok(10), fn(value) { 92 Ok({ value + 2 } * 4) 93 }) 94} 95" 96 ); 97} 98 99#[test] 100fn inline_function_which_calls_other_function() { 101 // This function calls `result.try`, meaning this must be inlined twice to 102 // achieve the desired result. 103 assert_js!( 104 ("gleam_stdlib", "gleam/result", RESULT_MODULE), 105 ( 106 "gleam_stdlib", 107 "testing", 108 " 109import gleam/result.{try} 110 111pub fn always_inline(result, f) -> Result(b, e) { 112 try(result, f) 113} 114" 115 ), 116 " 117import testing 118 119pub fn main() { 120 testing.always_inline(Ok(10), Error) 121} 122" 123 ); 124} 125 126#[test] 127fn inline_function_with_use() { 128 assert_js!( 129 ("gleam_stdlib", "gleam/bool", BOOL_MODULE), 130 " 131import gleam/bool 132 133pub fn divide(a, b) { 134 use <- bool.guard(when: b == 0, return: 0) 135 a / b 136} 137" 138 ); 139} 140 141#[test] 142fn inline_function_with_use_and_anonymous() { 143 assert_js!( 144 ("gleam_stdlib", "gleam/bool", BOOL_MODULE), 145 r#" 146import gleam/bool 147 148pub fn divide(a, b) { 149 use <- bool.lazy_guard(b == 0, fn() { panic as "Cannot divide by 0" }) 150 a / b 151} 152"# 153 ); 154} 155 156#[test] 157fn inline_function_with_use_becomes_tail_recursive() { 158 assert_js!( 159 ("gleam_stdlib", "gleam/bool", BOOL_MODULE), 160 " 161import gleam/bool 162 163pub fn count(from: Int, to: Int) -> Int { 164 use <- bool.guard(when: from >= to, return: from) 165 echo from 166 count(from + 1, to) 167} 168" 169 ); 170} 171 172#[test] 173fn do_not_inline_parameters_used_more_than_once() { 174 // Since the `something` parameter is used more than once in the body of the 175 // function, it should not be inlined, and should be assigned once at the 176 // beginning of the function. 177 assert_js!( 178 ( 179 "gleam_stdlib", 180 "testing", 181 " 182pub fn always_inline(something) { 183 case something { 184 True -> something 185 False -> False 186 } 187} 188" 189 ), 190 " 191import testing 192 193pub fn main() { 194 testing.always_inline(True) 195} 196" 197 ); 198} 199 200#[test] 201fn do_not_inline_parameters_that_have_side_effects() { 202 assert_js!( 203 ("gleam_stdlib", "gleam/result", RESULT_MODULE), 204 r#" 205import gleam/result 206 207pub fn main() { 208 result.map(Ok(10), do_side_effects()) 209} 210 211fn do_side_effects() { 212 let function = fn(x) { x + 1 } 213 panic as "Side effects" 214 function 215} 216"# 217 ); 218} 219 220#[test] 221fn inline_anonymous_function_call() { 222 assert_js!( 223 " 224pub fn main() { 225 fn(a, b) { #(a, b) }(42, False) 226} 227" 228 ); 229} 230 231#[test] 232fn inline_anonymous_function_in_pipe() { 233 assert_js!( 234 " 235pub fn main() { 236 1 |> fn(x) { x + 1 } |> fn(y) { y * y } 237} 238" 239 ); 240} 241 242#[test] 243fn inline_function_capture_in_pipe() { 244 // The function capture is desugared to an anonymous function, so it should 245 // be turned into a direct call to `add` 246 assert_js!( 247 " 248pub fn main() { 249 1 |> add(4, _) 250} 251 252fn add(a, b) { a + b } 253" 254 ); 255} 256 257#[test] 258fn inlining_works_through_blocks() { 259 assert_js!( 260 " 261pub fn main() { 262 { fn(x) { Ok(x + 1) } }(41) 263} 264" 265 ); 266} 267 268#[test] 269fn blocks_get_preserved_when_needed() { 270 assert_js!( 271 " 272pub fn main() { 273 { 4 |> make_adder }(6) 274} 275 276fn make_adder(a) { 277 fn(b) { a + b } 278} 279" 280 ); 281} 282 283#[test] 284fn blocks_get_preserved_when_needed2() { 285 assert_js!( 286 " 287pub fn main() { 288 fn(x) { 1 + x }(2) * 3 289} 290" 291 ); 292} 293 294#[test] 295fn parameters_from_nested_functions_are_correctly_inlined() { 296 assert_js!( 297 ("gleam_stdlib", "gleam/result", RESULT_MODULE), 298 " 299import gleam/result 300 301pub fn halve_all(a, b, c) { 302 use x <- result.try(divide(a, 2)) 303 use y <- result.try(divide(b, 2)) 304 use z <- result.map(divide(c, 2)) 305 306 #(x, y, z) 307} 308 309fn divide(a, b) { 310 case a % b { 311 0 -> Ok(a / b) 312 _ -> Error(Nil) 313 } 314} 315" 316 ); 317} 318 319// https://github.com/gleam-lang/gleam/issues/4852 320#[test] 321fn inlining_works_properly_with_record_updates() { 322 assert_js!( 323 ("gleam_stdlib", "gleam/result", RESULT_MODULE), 324 " 325import gleam/result 326 327pub type Wibble { 328 Wibble(a: Int, b: Int) 329} 330 331pub fn main() { 332 let w = Wibble(1, 2) 333 use b <- result.map(Ok(3)) 334 Wibble(..w, b:) 335} 336" 337 ); 338} 339 340// https://github.com/gleam-lang/gleam/issues/4877 341#[test] 342fn inline_shadowed_variable() { 343 assert_js!( 344 " 345pub fn main() { 346 let a = 10 347 let b = 20 348 349 fn(x) { 350 let a = 7 351 x + a 352 }(a + b) 353 354 a 355} 356" 357 ); 358} 359 360#[test] 361fn inline_variable_shadowing_parameter() { 362 assert_js!( 363 " 364pub fn sum(a, b) { 365 fn(x) { 366 let a = 7 367 x + a 368 }(a + b) 369 370 a 371} 372" 373 ); 374} 375 376#[test] 377fn inline_shadowed_variable_nested() { 378 assert_js!( 379 " 380pub fn sum(a, b) { 381 fn(x) { 382 let a = 7 383 fn(y) { 384 let a = 10 385 y - a 386 }(x + a) 387 388 a 389 }(a + b) 390 391 a 392} 393" 394 ); 395} 396 397#[test] 398fn inline_variable_shadowed_in_case_pattern() { 399 assert_js!( 400 " 401pub fn sum() { 402 let a = 10 403 let b = 20 404 405 fn(x) { 406 case 7, 8 { 407 a, b -> a + b + x 408 } 409 }(a + b) 410 411 a + b 412} 413" 414 ); 415} 416 417#[test] 418fn inline_variable_shadowing_case_pattern() { 419 assert_js!( 420 " 421pub fn sum() { 422 case 1, 2 { 423 a, b -> fn(x) { 424 let a = 7 425 x + a 426 }(a + b) 427 } 428} 429" 430 ); 431}