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