From 867554ad7c571adea299ecb7ad99641ee22dc91b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 13 Jan 2022 15:44:17 -0800 Subject: [PATCH] Fix suggesting turbofish with lifetime arguments --- .../rustc_parse/src/parser/diagnostics.rs | 39 +++++++------ compiler/rustc_parse/src/parser/expr.rs | 8 ++- ...st-missing-braces-without-turbofish.stderr | 24 ++++---- src/test/ui/did_you_mean/issue-40396.stderr | 14 ++--- .../require-parens-for-chained-comparison.rs | 24 +++++--- ...quire-parens-for-chained-comparison.stderr | 55 +++++++++++++++---- src/test/ui/suggestions/issue-82566-1.stderr | 6 +- src/test/ui/suggestions/issue-82566-2.stderr | 6 +- 8 files changed, 115 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 4121a759c37..19d6de09dae 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -27,7 +27,7 @@ use std::mem::take; use tracing::{debug, trace}; const TURBOFISH_SUGGESTION_STR: &str = - "use `::<...>` instead of `<...>` to specify type or const arguments"; + "use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments"; /// Creates a placeholder argument. pub(super) fn dummy_arg(ident: Ident) -> Param { @@ -731,21 +731,28 @@ impl<'a> Parser<'a> { match x { Ok((_, _, false)) => { if self.eat(&token::Gt) { - match self.parse_expr() { - Ok(_) => { - e.span_suggestion_verbose( - binop.span.shrink_to_lo(), - TURBOFISH_SUGGESTION_STR, - "::".to_string(), - Applicability::MaybeIncorrect, - ); - e.emit(); - *expr = - self.mk_expr_err(expr.span.to(self.prev_token.span)); - return Ok(()); - } - Err(mut err) => { - err.cancel(); + let turbo_err = e.span_suggestion_verbose( + binop.span.shrink_to_lo(), + TURBOFISH_SUGGESTION_STR, + "::".to_string(), + Applicability::MaybeIncorrect, + ); + if self.check(&TokenKind::Semi) { + turbo_err.emit(); + *expr = self.mk_expr_err(expr.span); + return Ok(()); + } else { + match self.parse_expr() { + Ok(_) => { + turbo_err.emit(); + *expr = self + .mk_expr_err(expr.span.to(self.prev_token.span)); + return Ok(()); + } + Err(mut err) => { + turbo_err.cancel(); + err.cancel(); + } } } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index f706a98a4fc..6991670f800 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1443,7 +1443,7 @@ impl<'a> Parser<'a> { &mut self, label: Label, attrs: AttrVec, - consume_colon: bool, + mut consume_colon: bool, ) -> PResult<'a, P> { let lo = label.ident.span; let label = Some(label); @@ -1456,6 +1456,12 @@ impl<'a> Parser<'a> { self.parse_loop_expr(label, lo, attrs) } else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() { self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs) + } else if !ate_colon && (self.check(&TokenKind::Comma) || self.check(&TokenKind::Gt)) { + // We're probably inside of a `Path<'a>` that needs a turbofish, so suppress the + // "must be followed by a colon" error. + self.diagnostic().delay_span_bug(lo, "this label wasn't parsed correctly"); + consume_colon = false; + Ok(self.mk_expr_err(lo)) } else { let msg = "expected `while`, `for`, `loop` or `{` after a label"; self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit(); diff --git a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces-without-turbofish.stderr b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces-without-turbofish.stderr index 11c3481f15a..a6825b84589 100644 --- a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces-without-turbofish.stderr +++ b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces-without-turbofish.stderr @@ -4,7 +4,7 @@ error: comparison operators cannot be chained LL | foo(); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | foo::(); | ++ @@ -15,7 +15,7 @@ error: comparison operators cannot be chained LL | foo(); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | foo::(); | ++ @@ -26,7 +26,7 @@ error: comparison operators cannot be chained LL | foo<3 + 3>(); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | foo::<3 + 3>(); | ++ @@ -37,7 +37,7 @@ error: comparison operators cannot be chained LL | foo(); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | foo::(); | ++ @@ -48,7 +48,7 @@ error: comparison operators cannot be chained LL | foo(); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | foo::(); | ++ @@ -59,7 +59,7 @@ error: comparison operators cannot be chained LL | foo<100 - BAR>(); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | foo::<100 - BAR>(); | ++ @@ -70,7 +70,7 @@ error: comparison operators cannot be chained LL | foo()>(); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | foo::()>(); | ++ @@ -87,7 +87,7 @@ error: comparison operators cannot be chained LL | foo()>(); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | foo::()>(); | ++ @@ -98,7 +98,7 @@ error: comparison operators cannot be chained LL | foo() + BAR>(); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | foo::() + BAR>(); | ++ @@ -109,7 +109,7 @@ error: comparison operators cannot be chained LL | foo() - BAR>(); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | foo::() - BAR>(); | ++ @@ -120,7 +120,7 @@ error: comparison operators cannot be chained LL | foo()>(); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | foo::()>(); | ++ @@ -131,7 +131,7 @@ error: comparison operators cannot be chained LL | foo()>(); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | foo::()>(); | ++ diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr index d2938435ece..d0249efd094 100644 --- a/src/test/ui/did_you_mean/issue-40396.stderr +++ b/src/test/ui/did_you_mean/issue-40396.stderr @@ -4,7 +4,7 @@ error: comparison operators cannot be chained LL | (0..13).collect>(); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | (0..13).collect::>(); | ++ @@ -15,7 +15,7 @@ error: comparison operators cannot be chained LL | Vec::new(); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | Vec::::new(); | ++ @@ -26,7 +26,7 @@ error: comparison operators cannot be chained LL | (0..13).collect(); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | (0..13).collect::(); | ++ @@ -37,7 +37,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, fo LL | let x = std::collections::HashMap::new(); | ^ expected one of 8 possible tokens | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | let x = std::collections::HashMap::::new(); | ++ @@ -48,7 +48,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found LL | std::collections::HashMap::new() | ^ expected one of 8 possible tokens | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | std::collections::HashMap::::new() | ++ @@ -59,7 +59,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found LL | std::collections::HashMap::new(); | ^ expected one of 8 possible tokens | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | std::collections::HashMap::::new(); | ++ @@ -70,7 +70,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found LL | std::collections::HashMap::new(1, 2); | ^ expected one of 8 possible tokens | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | std::collections::HashMap::::new(1, 2); | ++ diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.rs b/src/test/ui/parser/require-parens-for-chained-comparison.rs index e3ce6cd39bc..68636f6b907 100644 --- a/src/test/ui/parser/require-parens-for-chained-comparison.rs +++ b/src/test/ui/parser/require-parens-for-chained-comparison.rs @@ -1,6 +1,3 @@ -fn f() {} -struct X; - fn main() { false == false == false; //~^ ERROR comparison operators cannot be chained @@ -12,15 +9,26 @@ fn main() { f(); //~^ ERROR comparison operators cannot be chained - //~| HELP use `::<...>` instead of `<...>` to specify type or const arguments + //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments f, Option>>(1, 2); //~^ ERROR comparison operators cannot be chained - //~| HELP use `::<...>` instead of `<...>` to specify type or const arguments + //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments - use std::convert::identity; - let _ = identity; + let _ = f(); + //~^ ERROR expected one of + //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + + let _ = f<'_, i8>(); + //~^ ERROR expected one of + //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + + f<'_>(); + //~^ comparison operators cannot be chained + //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + + let _ = f; //~^ ERROR comparison operators cannot be chained - //~| HELP use `::<...>` instead of `<...>` to specify type or const arguments + //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments //~| HELP or use `(...)` if you meant to specify fn arguments } diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.stderr b/src/test/ui/parser/require-parens-for-chained-comparison.stderr index 74429cb438c..cde6f8c674f 100644 --- a/src/test/ui/parser/require-parens-for-chained-comparison.stderr +++ b/src/test/ui/parser/require-parens-for-chained-comparison.stderr @@ -1,5 +1,5 @@ error: comparison operators cannot be chained - --> $DIR/require-parens-for-chained-comparison.rs:5:11 + --> $DIR/require-parens-for-chained-comparison.rs:2:11 | LL | false == false == false; | ^^ ^^ @@ -10,7 +10,7 @@ LL | false == false && false == false; | ++++++++ error: comparison operators cannot be chained - --> $DIR/require-parens-for-chained-comparison.rs:9:11 + --> $DIR/require-parens-for-chained-comparison.rs:6:11 | LL | false == 0 < 2; | ^^ ^ @@ -21,35 +21,68 @@ LL | false == (0 < 2); | + + error: comparison operators cannot be chained - --> $DIR/require-parens-for-chained-comparison.rs:13:6 + --> $DIR/require-parens-for-chained-comparison.rs:10:6 | LL | f(); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | f::(); | ++ error: comparison operators cannot be chained - --> $DIR/require-parens-for-chained-comparison.rs:17:6 + --> $DIR/require-parens-for-chained-comparison.rs:14:6 | LL | f, Option>>(1, 2); | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | f::, Option>>(1, 2); | ++ +error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `,` + --> $DIR/require-parens-for-chained-comparison.rs:18:17 + | +LL | let _ = f(); + | ^ expected one of 8 possible tokens + | +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + | +LL | let _ = f::(); + | ++ + +error: expected one of `.`, `:`, `;`, `?`, `else`, `for`, `loop`, `while`, `{`, or an operator, found `,` + --> $DIR/require-parens-for-chained-comparison.rs:22:17 + | +LL | let _ = f<'_, i8>(); + | ^ expected one of 10 possible tokens + | +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + | +LL | let _ = f::<'_, i8>(); + | ++ + error: comparison operators cannot be chained - --> $DIR/require-parens-for-chained-comparison.rs:22:21 + --> $DIR/require-parens-for-chained-comparison.rs:26:6 | -LL | let _ = identity; - | ^ ^ +LL | f<'_>(); + | ^ ^ | - = help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + | +LL | f::<'_>(); + | ++ + +error: comparison operators cannot be chained + --> $DIR/require-parens-for-chained-comparison.rs:30:14 + | +LL | let _ = f; + | ^ ^ + | + = help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments = help: or use `(...)` if you meant to specify fn arguments -error: aborting due to 5 previous errors +error: aborting due to 8 previous errors diff --git a/src/test/ui/suggestions/issue-82566-1.stderr b/src/test/ui/suggestions/issue-82566-1.stderr index a05c59c786b..72f0f45fb83 100644 --- a/src/test/ui/suggestions/issue-82566-1.stderr +++ b/src/test/ui/suggestions/issue-82566-1.stderr @@ -4,7 +4,7 @@ error: comparison operators cannot be chained LL | T1<1>::C; | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | T1::<1>::C; | ++ @@ -15,7 +15,7 @@ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` LL | T2<1, 2>::C; | ^ expected one of `.`, `;`, `?`, `}`, or an operator | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | T2::<1, 2>::C; | ++ @@ -26,7 +26,7 @@ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` LL | T3<1, 2, 3>::C; | ^ expected one of `.`, `;`, `?`, `}`, or an operator | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | T3::<1, 2, 3>::C; | ++ diff --git a/src/test/ui/suggestions/issue-82566-2.stderr b/src/test/ui/suggestions/issue-82566-2.stderr index 8f30a301bb8..ef9a414307c 100644 --- a/src/test/ui/suggestions/issue-82566-2.stderr +++ b/src/test/ui/suggestions/issue-82566-2.stderr @@ -4,7 +4,7 @@ error: comparison operators cannot be chained LL | fn foo1() -> [(); Foo1<10>::SUM] { | ^ ^ | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | fn foo1() -> [(); Foo1::<10>::SUM] { | ++ @@ -15,7 +15,7 @@ error: expected one of `.`, `?`, `]`, or an operator, found `,` LL | fn foo2() -> [(); Foo2<10, 20>::SUM] { | ^ expected one of `.`, `?`, `]`, or an operator | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | fn foo2() -> [(); Foo2::<10, 20>::SUM] { | ++ @@ -26,7 +26,7 @@ error: expected one of `.`, `?`, `]`, or an operator, found `,` LL | fn foo3() -> [(); Foo3<10, 20, 30>::SUM] { | ^ expected one of `.`, `?`, `]`, or an operator | -help: use `::<...>` instead of `<...>` to specify type or const arguments +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | LL | fn foo3() -> [(); Foo3::<10, 20, 30>::SUM] { | ++