···110110 check in an `assert`.
111111 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
112112113113+- Fixed a bug where the compiler would generate invalid code on the JavaScript
114114+ target for some `case` expressions using clause guards.
115115+ ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
116116+113117- The formatter no longer stack overflows trying to format lists with many
114118 items.
115119 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
···3131 subjects: &'a [TypedExpr],
3232 expression_generator: &mut Generator<'_, 'a>,
3333) -> Document<'a> {
3434+ let scope_position = expression_generator.scope_position.clone();
3435 let mut variables = Variables::new(expression_generator, VariableAssignment::Declare);
3536 let assignments = variables.assign_case_subjects(compiled_case, subjects);
3636- let decision = CasePrinter {
3737+ let mut printer = CasePrinter {
3738 variables,
3839 assignments: &assignments,
3940 kind: DecisionKind::Case { clauses },
4040- }
4141- .decision(&compiled_case.tree);
4141+ };
42424343- docvec![assignments_to_doc(assignments), decision.into_doc()].force_break()
4343+ let decision = match &compiled_case.tree {
4444+ // Printing needs extra care if we're dealing with a sort of "degenerate"
4545+ // tree that immediately starts with a guard node.
4646+ // Code generation for guard nodes require defining variables outside of
4747+ // the safe scope of the generated `if` statement. So if we were to just
4848+ // generate code like usual we run the risk of leaking variables in the
4949+ // outer scope:
5050+ //
5151+ // ```case
5252+ // case 11 {
5353+ // n if n == 10 -> todo
5454+ // _ -> todo
5555+ // }
5656+ //
5757+ // let n = 12
5858+ // ```
5959+ //
6060+ // That case would have us generate something like this:
6161+ //
6262+ // ```js
6363+ // let n = 11
6464+ // if (n === 10) { todo } else { todo }
6565+ //
6666+ // // If we don't wrap it in a block that `n = 11` definition that was
6767+ // // introduced would end up clashing with the `let n = 12` that comes
6868+ // // later!
6969+ // ```
7070+ //
7171+ // So in this special case we have to wrap everything in a block.
7272+ tree @ Decision::Guard { .. } if !scope_position.is_tail() => break_block(
7373+ printer
7474+ .inside_new_scope(|this| this.decision(tree))
7575+ .into_doc(),
7676+ ),
7777+7878+ tree @ Decision::Run { .. }
7979+ | tree @ Decision::Guard { .. }
8080+ | tree @ Decision::Switch { .. }
8181+ | tree @ Decision::Fail => printer.decision(tree).into_doc(),
8282+ };
8383+ docvec![assignments_to_doc(assignments), decision].force_break()
4484}
45854686/// The generated code for a decision tree.
···887887"#
888888 )
889889}
890890+891891+#[test]
892892+// https://github.com/gleam-lang/gleam/issues/5283
893893+fn duplicate_name_for_variables_used_in_guards() {
894894+ assert_js!(
895895+ r#"
896896+pub fn wibble() {
897897+ let a = case 1337 {
898898+ n if n == 1347 -> Nil
899899+ _ -> Nil
900900+ }
901901+ let b = case 1337 {
902902+ n -> Nil
903903+ }
904904+}"#
905905+ )
906906+}
907907+908908+#[test]
909909+// https://github.com/gleam-lang/gleam/issues/5283
910910+fn duplicate_name_for_variables_used_in_guards_shadowing_outer_name() {
911911+ assert_js!(
912912+ r#"
913913+pub fn wibble() {
914914+ let n = 1
915915+ let a = case 1337 {
916916+ n if n == 1347 -> n
917917+ _ -> n
918918+ }
919919+ let b = case 1337 {
920920+ n -> Nil
921921+ }
922922+}"#
923923+ )
924924+}
···11+---
22+source: compiler-core/src/javascript/tests/case.rs
33+expression: "\npub fn wibble() {\n let a = case 1337 {\n n if n == 1347 -> Nil\n _ -> Nil\n }\n let b = case 1337 {\n n -> Nil\n }\n}"
44+---
55+----- SOURCE CODE
66+77+pub fn wibble() {
88+ let a = case 1337 {
99+ n if n == 1347 -> Nil
1010+ _ -> Nil
1111+ }
1212+ let b = case 1337 {
1313+ n -> Nil
1414+ }
1515+}
1616+1717+----- COMPILED JAVASCRIPT
1818+export function wibble() {
1919+ let _block;
2020+ let $ = 1337;
2121+ {
2222+ let n = $;
2323+ if (n === 1347) {
2424+ _block = undefined;
2525+ } else {
2626+ _block = undefined;
2727+ }
2828+ }
2929+ let a = _block;
3030+ let _block$1;
3131+ let $1 = 1337;
3232+ let n = $1;
3333+ _block$1 = undefined;
3434+ let b = _block$1;
3535+ return b;
3636+}
···11+---
22+source: compiler-core/src/javascript/tests/case.rs
33+expression: "\npub fn wibble() {\n let n = 1\n let a = case 1337 {\n n if n == 1347 -> n\n _ -> n\n }\n let b = case 1337 {\n n -> Nil\n }\n}"
44+---
55+----- SOURCE CODE
66+77+pub fn wibble() {
88+ let n = 1
99+ let a = case 1337 {
1010+ n if n == 1347 -> n
1111+ _ -> n
1212+ }
1313+ let b = case 1337 {
1414+ n -> Nil
1515+ }
1616+}
1717+1818+----- COMPILED JAVASCRIPT
1919+export function wibble() {
2020+ let n = 1;
2121+ let _block;
2222+ let $ = 1337;
2323+ {
2424+ let n$1 = $;
2525+ if (n$1 === 1347) {
2626+ _block = $;
2727+ } else {
2828+ _block = n;
2929+ }
3030+ }
3131+ let a = _block;
3232+ let _block$1;
3333+ let $1 = 1337;
3434+ let n$1 = $1;
3535+ _block$1 = undefined;
3636+ let b = _block$1;
3737+ return b;
3838+}
···548548 _ -> False
549549 }
550550}
551551+552552+// https://github.com/gleam-lang/gleam/issues/5283
553553+pub fn case_with_guard_does_not_pollute_outer_scope_test() {
554554+ let a = case 1337 {
555555+ n if n == 1347 -> 1
556556+ _ -> 2
557557+ }
558558+ let b = case 1337 {
559559+ n -> 2
560560+ }
561561+ assert a == b
562562+}