diff options
| author | bors <bors@rust-lang.org> | 2020-09-15 10:14:52 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-09-15 10:14:52 +0000 |
| commit | 90b1f5ae59291dd69d72fad41a22277df19dc953 (patch) | |
| tree | 48be81f25a8a51daf3a29911988d58044341f67f /compiler/rustc_parse/src | |
| parent | c1589cc819ba7cf289c3ccbab30c215f0a6ba7d7 (diff) | |
| parent | 62effcbd5bfaf74e99def3e9a660dba9728b0b47 (diff) | |
| download | rust-90b1f5ae59291dd69d72fad41a22277df19dc953.tar.gz rust-90b1f5ae59291dd69d72fad41a22277df19dc953.zip | |
Auto merge of #76171 - estebank:turbofish-the-revenge, r=davidtwco
Detect turbofish with multiple type params missing leading `::` Fix #76072.
Diffstat (limited to 'compiler/rustc_parse/src')
| -rw-r--r-- | compiler/rustc_parse/src/parser/diagnostics.rs | 46 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/stmt.rs | 26 |
2 files changed, 66 insertions, 6 deletions
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index e2a735188f9..9ab13db4b5f 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -553,6 +553,52 @@ impl<'a> Parser<'a> { } } + /// When writing a turbofish with multiple type parameters missing the leading `::`, we will + /// encounter a parse error when encountering the first `,`. + pub(super) fn check_mistyped_turbofish_with_multiple_type_params( + &mut self, + mut e: DiagnosticBuilder<'a>, + expr: &mut P<Expr>, + ) -> PResult<'a, ()> { + if let ExprKind::Binary(binop, _, _) = &expr.kind { + if let ast::BinOpKind::Lt = binop.node { + if self.eat(&token::Comma) { + let x = self.parse_seq_to_before_end( + &token::Gt, + SeqSep::trailing_allowed(token::Comma), + |p| p.parse_ty(), + ); + match x { + Ok((_, _, false)) => { + self.bump(); // `>` + match self.parse_expr() { + Ok(_) => { + e.span_suggestion_verbose( + binop.span.shrink_to_lo(), + "use `::<...>` instead of `<...>` to specify type arguments", + "::".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(); + } + } + } + Err(mut err) => { + err.cancel(); + } + _ => {} + } + } + } + } + Err(e) + } + /// Check to see if a pair of chained operators looks like an attempt at chained comparison, /// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or /// parenthesising the leftmost comparison. diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 64b959e8325..fd1c6b25aec 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -364,7 +364,7 @@ impl<'a> Parser<'a> { let mut eat_semi = true; match stmt.kind { // Expression without semicolon. - StmtKind::Expr(ref expr) + StmtKind::Expr(ref mut expr) if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => { // Just check for errors and recover; do not eat semicolon yet. @@ -388,15 +388,29 @@ impl<'a> Parser<'a> { ); } } - e.emit(); - self.recover_stmt(); + if let Err(mut e) = + self.check_mistyped_turbofish_with_multiple_type_params(e, expr) + { + e.emit(); + self.recover_stmt(); + } // Don't complain about type errors in body tail after parse error (#57383). let sp = expr.span.to(self.prev_token.span); - stmt.kind = StmtKind::Expr(self.mk_expr_err(sp)); + *expr = self.mk_expr_err(sp); } } - StmtKind::Local(..) => { - self.expect_semi()?; + StmtKind::Local(ref mut local) => { + if let Err(e) = self.expect_semi() { + // We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover. + match &mut local.init { + Some(ref mut expr) => { + self.check_mistyped_turbofish_with_multiple_type_params(e, expr)?; + // We found `foo<bar, baz>`, have we fully recovered? + self.expect_semi()?; + } + None => return Err(e), + } + } eat_semi = false; } StmtKind::Empty => eat_semi = false, |
