From fb631a55c2acfae37e55e4c338dd3cc03da0fa7f Mon Sep 17 00:00:00 2001 From: Ömer Sinan Ağacan Date: Sat, 27 Feb 2021 08:01:32 +0300 Subject: Fix turbofish recovery with multiple generic args check_mistyped_turbofish_with_multiple_type_params was previously expecting type arguments between angle brackets, which is not right, as we can also see const expressions. We now use generic argument parser instead of type parser. Test with one, two, and three generic arguments added to check consistentcy between 1. check_no_chained_comparison: Called after parsing a nested binop application like `x < A > ...` where angle brackets are interpreted as binary operators and `A` is an expression. 2. check_mistyped_turbofish_with_multiple_type_params: called by `parse_full_stmt` when we expect to see a semicolon after parsing an expression but don't see it. (In `T2<1, 2>::C;`, the expression is `T2 < 1`) --- compiler/rustc_parse/src/parser/diagnostics.rs | 2 +- compiler/rustc_parse/src/parser/path.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 5b4939b7407..f4ab3260d1a 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -662,7 +662,7 @@ impl<'a> Parser<'a> { let x = self.parse_seq_to_before_end( &token::Gt, SeqSep::trailing_allowed(token::Comma), - |p| p.parse_ty(), + |p| p.parse_generic_arg(), ); match x { Ok((_, _, false)) => { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 6b7059eecf4..9cc600d9ede 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -545,7 +545,7 @@ impl<'a> Parser<'a> { /// Parse a generic argument in a path segment. /// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`. - fn parse_generic_arg(&mut self) -> PResult<'a, Option> { + pub(super) fn parse_generic_arg(&mut self) -> PResult<'a, Option> { let start = self.token.span; let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { // Parse lifetime argument. -- cgit 1.4.1-3-g733a5 From 992b914b6bf41aae4212ea4e8ee09f8b16a31f28 Mon Sep 17 00:00:00 2001 From: Ömer Sinan Ağacan Date: Sat, 27 Feb 2021 13:37:50 +0300 Subject: Recover from X when parsing const expr This adds recovery when in array type syntax user writes [X; Y] instead of [X; Y::] Fixes #82566 Note that whenever we parse an expression and know that the next token cannot be `,`, we should be calling check_mistyped_turbofish_with_multiple_type_params for this recovery. Previously we only did this for statement parsing (e.g. `let x = f;`). We now also do it when parsing the length field in array type syntax. --- compiler/rustc_parse/src/parser/ty.rs | 12 ++++++++-- src/test/ui/suggestions/issue-82566-1.rs | 21 +++++++++++++++++ src/test/ui/suggestions/issue-82566-1.stderr | 35 ++++++++++++++++++++++++++++ src/test/ui/suggestions/issue-82566-2.rs | 31 ++++++++++++++++++++++++ src/test/ui/suggestions/issue-82566-2.stderr | 35 ++++++++++++++++++++++++++++ src/test/ui/suggestions/issue-82566.rs | 21 ----------------- src/test/ui/suggestions/issue-82566.stderr | 35 ---------------------------- 7 files changed, 132 insertions(+), 58 deletions(-) create mode 100644 src/test/ui/suggestions/issue-82566-1.rs create mode 100644 src/test/ui/suggestions/issue-82566-1.stderr create mode 100644 src/test/ui/suggestions/issue-82566-2.rs create mode 100644 src/test/ui/suggestions/issue-82566-2.stderr delete mode 100644 src/test/ui/suggestions/issue-82566.rs delete mode 100644 src/test/ui/suggestions/issue-82566.stderr (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 9553f5d09e8..8f03bfd4c3a 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -360,12 +360,20 @@ impl<'a> Parser<'a> { } Err(err) => return Err(err), }; + let ty = if self.eat(&token::Semi) { - TyKind::Array(elt_ty, self.parse_anon_const_expr()?) + let mut length = self.parse_anon_const_expr()?; + if let Err(e) = self.expect(&token::CloseDelim(token::Bracket)) { + // Try to recover from `X` when `X::` works + self.check_mistyped_turbofish_with_multiple_type_params(e, &mut length.value)?; + self.expect(&token::CloseDelim(token::Bracket))?; + } + TyKind::Array(elt_ty, length) } else { + self.expect(&token::CloseDelim(token::Bracket))?; TyKind::Slice(elt_ty) }; - self.expect(&token::CloseDelim(token::Bracket))?; + Ok(ty) } diff --git a/src/test/ui/suggestions/issue-82566-1.rs b/src/test/ui/suggestions/issue-82566-1.rs new file mode 100644 index 00000000000..95c31fbaa28 --- /dev/null +++ b/src/test/ui/suggestions/issue-82566-1.rs @@ -0,0 +1,21 @@ +struct T1; +struct T2; +struct T3; + +impl T1<1> { + const C: () = (); +} + +impl T2<1, 2> { + const C: () = (); +} + +impl T3<1, 2, 3> { + const C: () = (); +} + +fn main() { + T1<1>::C; //~ ERROR: comparison operators cannot be chained + T2<1, 2>::C; //~ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + T3<1, 2, 3>::C; //~ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` +} diff --git a/src/test/ui/suggestions/issue-82566-1.stderr b/src/test/ui/suggestions/issue-82566-1.stderr new file mode 100644 index 00000000000..5a9099a894c --- /dev/null +++ b/src/test/ui/suggestions/issue-82566-1.stderr @@ -0,0 +1,35 @@ +error: comparison operators cannot be chained + --> $DIR/issue-82566-1.rs:18:7 + | +LL | T1<1>::C; + | ^ ^ + | +help: use `::<...>` instead of `<...>` to specify type or const arguments + | +LL | T1::<1>::C; + | ^^ + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + --> $DIR/issue-82566-1.rs:19:9 + | +LL | T2<1, 2>::C; + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + | +help: use `::<...>` instead of `<...>` to specify type or const arguments + | +LL | T2::<1, 2>::C; + | ^^ + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + --> $DIR/issue-82566-1.rs:20:9 + | +LL | T3<1, 2, 3>::C; + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + | +help: use `::<...>` instead of `<...>` to specify type or const arguments + | +LL | T3::<1, 2, 3>::C; + | ^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/suggestions/issue-82566-2.rs b/src/test/ui/suggestions/issue-82566-2.rs new file mode 100644 index 00000000000..80c8034bd0a --- /dev/null +++ b/src/test/ui/suggestions/issue-82566-2.rs @@ -0,0 +1,31 @@ +struct Foo1; +struct Foo2; +struct Foo3; + +impl Foo1 { + const SUM: usize = N1; +} + +impl Foo2 { + const SUM: usize = N1 + N2; +} + +impl Foo3 { + const SUM: usize = N1 + N2 + N3; +} + +fn foo1() -> [(); Foo1<10>::SUM] { //~ ERROR: comparison operators cannot be chained + todo!() +} + +fn foo2() -> [(); Foo2<10, 20>::SUM] { + //~^ ERROR: expected one of `.`, `?`, `]`, or an operator, found `,` + todo!() +} + +fn foo3() -> [(); Foo3<10, 20, 30>::SUM] { + //~^ ERROR: expected one of `.`, `?`, `]`, or an operator, found `,` + todo!() +} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-82566-2.stderr b/src/test/ui/suggestions/issue-82566-2.stderr new file mode 100644 index 00000000000..ea391ee078c --- /dev/null +++ b/src/test/ui/suggestions/issue-82566-2.stderr @@ -0,0 +1,35 @@ +error: comparison operators cannot be chained + --> $DIR/issue-82566-2.rs:17:23 + | +LL | fn foo1() -> [(); Foo1<10>::SUM] { + | ^ ^ + | +help: use `::<...>` instead of `<...>` to specify type or const arguments + | +LL | fn foo1() -> [(); Foo1::<10>::SUM] { + | ^^ + +error: expected one of `.`, `?`, `]`, or an operator, found `,` + --> $DIR/issue-82566-2.rs:21:26 + | +LL | fn foo2() -> [(); Foo2<10, 20>::SUM] { + | ^ expected one of `.`, `?`, `]`, or an operator + | +help: use `::<...>` instead of `<...>` to specify type or const arguments + | +LL | fn foo2() -> [(); Foo2::<10, 20>::SUM] { + | ^^ + +error: expected one of `.`, `?`, `]`, or an operator, found `,` + --> $DIR/issue-82566-2.rs:26:26 + | +LL | fn foo3() -> [(); Foo3<10, 20, 30>::SUM] { + | ^ expected one of `.`, `?`, `]`, or an operator + | +help: use `::<...>` instead of `<...>` to specify type or const arguments + | +LL | fn foo3() -> [(); Foo3::<10, 20, 30>::SUM] { + | ^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/suggestions/issue-82566.rs b/src/test/ui/suggestions/issue-82566.rs deleted file mode 100644 index 95c31fbaa28..00000000000 --- a/src/test/ui/suggestions/issue-82566.rs +++ /dev/null @@ -1,21 +0,0 @@ -struct T1; -struct T2; -struct T3; - -impl T1<1> { - const C: () = (); -} - -impl T2<1, 2> { - const C: () = (); -} - -impl T3<1, 2, 3> { - const C: () = (); -} - -fn main() { - T1<1>::C; //~ ERROR: comparison operators cannot be chained - T2<1, 2>::C; //~ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` - T3<1, 2, 3>::C; //~ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` -} diff --git a/src/test/ui/suggestions/issue-82566.stderr b/src/test/ui/suggestions/issue-82566.stderr deleted file mode 100644 index e13c097e4cc..00000000000 --- a/src/test/ui/suggestions/issue-82566.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error: comparison operators cannot be chained - --> $DIR/issue-82566.rs:18:7 - | -LL | T1<1>::C; - | ^ ^ - | -help: use `::<...>` instead of `<...>` to specify type or const arguments - | -LL | T1::<1>::C; - | ^^ - -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` - --> $DIR/issue-82566.rs:19:9 - | -LL | T2<1, 2>::C; - | ^ expected one of `.`, `;`, `?`, `}`, or an operator - | -help: use `::<...>` instead of `<...>` to specify type or const arguments - | -LL | T2::<1, 2>::C; - | ^^ - -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` - --> $DIR/issue-82566.rs:20:9 - | -LL | T3<1, 2, 3>::C; - | ^ expected one of `.`, `;`, `?`, `}`, or an operator - | -help: use `::<...>` instead of `<...>` to specify type or const arguments - | -LL | T3::<1, 2, 3>::C; - | ^^ - -error: aborting due to 3 previous errors - -- cgit 1.4.1-3-g733a5