diff --git a/crates/compiler/fmt/src/annotation.rs b/crates/compiler/fmt/src/annotation.rs index b279a8fc9c..3e6b18a158 100644 --- a/crates/compiler/fmt/src/annotation.rs +++ b/crates/compiler/fmt/src/annotation.rs @@ -38,6 +38,7 @@ pub enum Parens { InFunctionType, InApply, InOperator, + InAsPattern, } /// In an AST node, do we show newlines around it diff --git a/crates/compiler/fmt/src/expr.rs b/crates/compiler/fmt/src/expr.rs index 12b3b8c48e..8b7a6ea147 100644 --- a/crates/compiler/fmt/src/expr.rs +++ b/crates/compiler/fmt/src/expr.rs @@ -1245,7 +1245,7 @@ fn fmt_closure<'a>( let mut it = loc_patterns.iter().peekable(); while let Some(loc_pattern) = it.next() { - loc_pattern.format(buf, indent); + loc_pattern.format_with_options(buf, Parens::InAsPattern, Newlines::No, indent); if it.peek().is_some() { buf.indent(indent); diff --git a/crates/compiler/fmt/src/pattern.rs b/crates/compiler/fmt/src/pattern.rs index 015c739a58..dbde68c8fa 100644 --- a/crates/compiler/fmt/src/pattern.rs +++ b/crates/compiler/fmt/src/pattern.rs @@ -244,9 +244,19 @@ impl<'a> Formattable for Pattern<'a> { } As(pattern, pattern_as) => { + let needs_parens = parens == Parens::InAsPattern; + + if needs_parens { + buf.push('('); + } + fmt_pattern(buf, &pattern.value, indent, parens); pattern_as.format(buf, indent + INDENT); + + if needs_parens { + buf.push(')'); + } } // Space diff --git a/crates/compiler/test_mono/generated/as_pattern_in_closure_arg.txt b/crates/compiler/test_mono/generated/as_pattern_in_closure_arg.txt new file mode 100644 index 0000000000..5d25c983bf --- /dev/null +++ b/crates/compiler/test_mono/generated/as_pattern_in_closure_arg.txt @@ -0,0 +1,31 @@ +procedure Num.19 (#Attr.2, #Attr.3): + let Num.282 : I64 = lowlevel NumAdd #Attr.2 #Attr.3; + ret Num.282; + +procedure Test.1 (Test.12): + let Test.6 : I64 = StructAtIndex 0 Test.12; + let Test.5 : I64 = StructAtIndex 1 Test.12; + let Test.3 : I64 = StructAtIndex 2 Test.12; + let Test.4 : I64 = StructAtIndex 3 Test.12; + let Test.18 : I64 = CallByName Num.19 Test.3 Test.5; + let Test.19 : I64 = CallByName Num.19 Test.4 Test.6; + let Test.17 : {I64, I64} = Struct {Test.18, Test.19}; + ret Test.17; + +procedure Test.2 (Test.9): + let Test.7 : I64 = StructAtIndex 2 Test.9; + let Test.8 : I64 = StructAtIndex 3 Test.9; + let Test.16 : {I64, I64} = CallByName Test.1 Test.9; + let Test.10 : I64 = StructAtIndex 0 Test.16; + let Test.11 : I64 = StructAtIndex 1 Test.16; + let Test.15 : {I64, I64, I64, I64} = Struct {Test.7, Test.8, Test.10, Test.11}; + ret Test.15; + +procedure Test.0 (): + let Test.20 : I64 = 4i64; + let Test.21 : I64 = 3i64; + let Test.22 : I64 = 1i64; + let Test.23 : I64 = 2i64; + let Test.14 : {I64, I64, I64, I64} = Struct {Test.20, Test.21, Test.22, Test.23}; + let Test.13 : {I64, I64, I64, I64} = CallByName Test.2 Test.14; + ret Test.13; diff --git a/crates/compiler/test_mono/generated/opaque_as_pattern_in_closure_arg.txt b/crates/compiler/test_mono/generated/opaque_as_pattern_in_closure_arg.txt new file mode 100644 index 0000000000..834b3ee0f5 --- /dev/null +++ b/crates/compiler/test_mono/generated/opaque_as_pattern_in_closure_arg.txt @@ -0,0 +1,18 @@ +procedure Num.21 (#Attr.2, #Attr.3): + let Num.281 : U64 = lowlevel NumMul #Attr.2 #Attr.3; + ret Num.281; + +procedure Test.2 (Test.8): + let Test.14 : U64 = 2i64; + let Test.13 : U64 = CallByName Num.21 Test.8 Test.14; + ret Test.13; + +procedure Test.3 (Test.7): + let Test.12 : U64 = CallByName Test.2 Test.7; + let Test.11 : {U64, U64} = Struct {Test.7, Test.12}; + ret Test.11; + +procedure Test.0 (): + let Test.10 : U64 = 42i64; + let Test.9 : {U64, U64} = CallByName Test.3 Test.10; + ret Test.9; diff --git a/crates/compiler/test_mono/generated/record_as_pattern_in_closure_arg.txt b/crates/compiler/test_mono/generated/record_as_pattern_in_closure_arg.txt new file mode 100644 index 0000000000..5d25c983bf --- /dev/null +++ b/crates/compiler/test_mono/generated/record_as_pattern_in_closure_arg.txt @@ -0,0 +1,31 @@ +procedure Num.19 (#Attr.2, #Attr.3): + let Num.282 : I64 = lowlevel NumAdd #Attr.2 #Attr.3; + ret Num.282; + +procedure Test.1 (Test.12): + let Test.6 : I64 = StructAtIndex 0 Test.12; + let Test.5 : I64 = StructAtIndex 1 Test.12; + let Test.3 : I64 = StructAtIndex 2 Test.12; + let Test.4 : I64 = StructAtIndex 3 Test.12; + let Test.18 : I64 = CallByName Num.19 Test.3 Test.5; + let Test.19 : I64 = CallByName Num.19 Test.4 Test.6; + let Test.17 : {I64, I64} = Struct {Test.18, Test.19}; + ret Test.17; + +procedure Test.2 (Test.9): + let Test.7 : I64 = StructAtIndex 2 Test.9; + let Test.8 : I64 = StructAtIndex 3 Test.9; + let Test.16 : {I64, I64} = CallByName Test.1 Test.9; + let Test.10 : I64 = StructAtIndex 0 Test.16; + let Test.11 : I64 = StructAtIndex 1 Test.16; + let Test.15 : {I64, I64, I64, I64} = Struct {Test.7, Test.8, Test.10, Test.11}; + ret Test.15; + +procedure Test.0 (): + let Test.20 : I64 = 4i64; + let Test.21 : I64 = 3i64; + let Test.22 : I64 = 1i64; + let Test.23 : I64 = 2i64; + let Test.14 : {I64, I64, I64, I64} = Struct {Test.20, Test.21, Test.22, Test.23}; + let Test.13 : {I64, I64, I64, I64} = CallByName Test.2 Test.14; + ret Test.13; diff --git a/crates/compiler/test_mono/src/tests.rs b/crates/compiler/test_mono/src/tests.rs index 70f4de7abc..7bf1c53e83 100644 --- a/crates/compiler/test_mono/src/tests.rs +++ b/crates/compiler/test_mono/src/tests.rs @@ -657,6 +657,31 @@ fn record_optional_field_function_use_default() { " } +#[mono_test] +fn record_as_pattern_in_closure_arg() { + r" + f = \{x, y, w, h} -> (x + w, y + h) + + g = \({ x, y } as box) -> + (right, bottom) = f box + (x, y, right, bottom) + + g { x: 1, y: 2, w: 3, h: 4 } + " +} + +#[mono_test] +fn opaque_as_pattern_in_closure_arg() { + r" + Opaque := U64 + + f = \(@Opaque x) -> x * 2 + g = \(@Opaque x as s) -> (x, f s) + + g (@Opaque 42) + " +} + #[mono_test] fn quicksort_help() { // do we still need with_larger_debug_stack? diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/arg_pattern_as.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/arg_pattern_as.expr.formatted.roc new file mode 100644 index 0000000000..f0657bfe44 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/arg_pattern_as.expr.formatted.roc @@ -0,0 +1,2 @@ +\({ x, y } as point), (@Location inner as outer) -> + crash "" \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/arg_pattern_as.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/arg_pattern_as.expr.result-ast new file mode 100644 index 0000000000..dd339a58e5 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/arg_pattern_as.expr.result-ast @@ -0,0 +1,57 @@ +SpaceAfter( + Closure( + [ + @2-19 As( + @2-10 RecordDestructure( + [ + @4-5 Identifier { + ident: "x", + }, + @7-8 Identifier { + ident: "y", + }, + ], + ), + PatternAs { + spaces_before: [], + identifier: @14-19 "point", + }, + ), + @23-47 As( + @23-38 Apply( + @23-32 OpaqueRef( + "@Location", + ), + [ + @33-38 Identifier { + ident: "inner", + }, + ], + ), + PatternAs { + spaces_before: [], + identifier: @42-47 "outer", + }, + ), + ], + @56-64 SpaceBefore( + Apply( + @56-61 Crash, + [ + @62-64 Str( + PlainLine( + "", + ), + ), + ], + Space, + ), + [ + Newline, + ], + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/arg_pattern_as.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/arg_pattern_as.expr.roc new file mode 100644 index 0000000000..33fc763c72 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/arg_pattern_as.expr.roc @@ -0,0 +1,2 @@ +\({ x, y } as point), (@Location inner as outer) -> + crash "" diff --git a/crates/compiler/test_syntax/tests/test_snapshots.rs b/crates/compiler/test_syntax/tests/test_snapshots.rs index 2c4c1cc21e..9a14ee6903 100644 --- a/crates/compiler/test_syntax/tests/test_snapshots.rs +++ b/crates/compiler/test_syntax/tests/test_snapshots.rs @@ -281,6 +281,7 @@ mod test_snapshots { pass/apply_two_args.expr, pass/apply_unary_negation.expr, pass/apply_unary_not.expr, + pass/arg_pattern_as.expr, pass/basic_apply.expr, pass/basic_docs.expr, pass/basic_field.expr,