From 1be2075e7f3aacfa1d4ac6feac5d31cdee2b6b2c Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Mon, 2 Dec 2024 19:42:17 -0800 Subject: [PATCH] Make sure ext's can't slurp surrounding apply args --- crates/compiler/parse/src/type_annotation.rs | 46 ++++++++++++--- ...ply_tuple_ext_parens_ty.expr.formatted.roc | 2 + .../apply_tuple_ext_parens_ty.expr.result-ast | 58 +++++++++++++++++++ .../pass/apply_tuple_ext_parens_ty.expr.roc | 2 + .../test_syntax/tests/test_snapshots.rs | 1 + 5 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 crates/compiler/test_syntax/tests/snapshots/pass/apply_tuple_ext_parens_ty.expr.formatted.roc create mode 100644 crates/compiler/test_syntax/tests/snapshots/pass/apply_tuple_ext_parens_ty.expr.result-ast create mode 100644 crates/compiler/test_syntax/tests/snapshots/pass/apply_tuple_ext_parens_ty.expr.roc diff --git a/crates/compiler/parse/src/type_annotation.rs b/crates/compiler/parse/src/type_annotation.rs index 61e80c94e5..13f5e8ec7a 100644 --- a/crates/compiler/parse/src/type_annotation.rs +++ b/crates/compiler/parse/src/type_annotation.rs @@ -97,7 +97,7 @@ fn check_type_alias<'a>( fn parse_type_alias_after_as<'a>() -> impl Parser<'a, TypeHeader<'a>, EType<'a>> { then( - space0_before_e(term(false), EType::TAsIndentStart), + space0_before_e(term_or_apply_with_as(false), EType::TAsIndentStart), // TODO: introduce a better combinator for this. // `check_type_alias` doesn't need to modify the state or progress, but it needs to access `state.pos()` |arena, state, progress, output| { @@ -112,6 +112,28 @@ fn parse_type_alias_after_as<'a>() -> impl Parser<'a, TypeHeader<'a>, EType<'a>> } fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc>, EType<'a>> { + one_of!( + loc_wildcard(), + loc_inferred(), + specialize_err(EType::TInParens, loc_type_in_parens(stop_at_surface_has)), + loc(specialize_err( + EType::TRecord, + record_type(stop_at_surface_has) + )), + loc(specialize_err( + EType::TTagUnion, + tag_union_type(stop_at_surface_has) + )), + loc(specialize_err(EType::TApply, concrete_type())), + loc(parse_type_variable(stop_at_surface_has)), + fail(EType::TStart), + ) + .trace("type_annotation:term") +} + +fn term_or_apply_with_as<'a>( + stop_at_surface_has: bool, +) -> impl Parser<'a, Loc>, EType<'a>> { map_with_arena( and( one_of!( @@ -161,7 +183,7 @@ fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc } }, ) - .trace("type_annotation:term") + .trace("type_annotation:term_or_apply_with_as") } /// The `*` type variable, e.g. in (List *) Wildcard, @@ -579,8 +601,11 @@ fn expression<'a>( stop_at_surface_has: bool, ) -> impl Parser<'a, Loc>, EType<'a>> { (move |arena, state: State<'a>, min_indent: u32| { - let (p1, first, state) = space0_before_e(term(stop_at_surface_has), EType::TIndentStart) - .parse(arena, state, min_indent)?; + let (p1, first, state) = space0_before_e( + term_or_apply_with_as(stop_at_surface_has), + EType::TIndentStart, + ) + .parse(arena, state, min_indent)?; let (p2, rest, rest_state) = zero_or_more(skip_first( backtrackable(byte(b',', EType::TFunctionArgument)), @@ -588,7 +613,10 @@ fn expression<'a>( map_with_arena( and( backtrackable(space0_e(EType::TIndentStart)), - and(term(stop_at_surface_has), space0_e(EType::TIndentEnd)), + and( + term_or_apply_with_as(stop_at_surface_has), + space0_e(EType::TIndentEnd) + ), ), comma_args_help, ), @@ -614,9 +642,11 @@ fn expression<'a>( let (progress, annot, state) = match result { Ok((p3, (space_before_arrow, arrow), state)) => { - let (p4, return_type, state) = - space0_before_e(term(stop_at_surface_has), EType::TIndentStart) - .parse(arena, state, min_indent)?; + let (p4, return_type, state) = space0_before_e( + term_or_apply_with_as(stop_at_surface_has), + EType::TIndentStart, + ) + .parse(arena, state, min_indent)?; let region = Region::span_across(&first.region, &return_type.region); diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_tuple_ext_parens_ty.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tuple_ext_parens_ty.expr.formatted.roc new file mode 100644 index 0000000000..62bc3886f7 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tuple_ext_parens_ty.expr.formatted.roc @@ -0,0 +1,2 @@ +i : M ()Y c +t \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_tuple_ext_parens_ty.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tuple_ext_parens_ty.expr.result-ast new file mode 100644 index 0000000000..b892abb74c --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tuple_ext_parens_ty.expr.result-ast @@ -0,0 +1,58 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-10, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Annotation( + @0-1 Identifier { + ident: "i", + }, + @2-10 Apply( + "", + "M", + [ + @3-8 Tuple { + elems: [], + ext: Some( + @6-7 Apply( + "", + "Y", + [], + ), + ), + }, + @9-10 BoundVariable( + "c", + ), + ], + ), + ), + ], + }, + @11-12 SpaceBefore( + Var { + module_name: "", + ident: "t", + }, + [ + Newline, + ], + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_tuple_ext_parens_ty.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tuple_ext_parens_ty.expr.roc new file mode 100644 index 0000000000..3c47d32a83 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tuple_ext_parens_ty.expr.roc @@ -0,0 +1,2 @@ +i:M()(Y) c +t diff --git a/crates/compiler/test_syntax/tests/test_snapshots.rs b/crates/compiler/test_syntax/tests/test_snapshots.rs index 7025391fa4..a643151a46 100644 --- a/crates/compiler/test_syntax/tests/test_snapshots.rs +++ b/crates/compiler/test_syntax/tests/test_snapshots.rs @@ -306,6 +306,7 @@ mod test_snapshots { pass/apply_record_ann.expr, pass/apply_tag.expr, pass/apply_three_args.expr, + pass/apply_tuple_ext_parens_ty.expr, pass/apply_two_args.expr, pass/apply_unary_negation.expr, pass/apply_unary_not.expr,