diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 3244b35e89b0e..609a0c961e971 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -1,8 +1,10 @@ use super::ty::AllowPlus; use super::{BlockMode, Parser, PathStyle, SemiColonMode, SeqSep, TokenExpectType, TokenType}; -use rustc_ast::ast::{self, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Item, Param}; -use rustc_ast::ast::{AttrVec, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind}; +use rustc_ast::ast::{ + self, AngleBracketedArgs, AttrVec, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, + Item, ItemKind, Mutability, Param, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, +}; use rustc_ast::ptr::P; use rustc_ast::token::{self, Lit, LitKind, TokenKind}; use rustc_ast::util::parser::AssocOp; @@ -488,6 +490,57 @@ impl<'a> Parser<'a> { false } + /// Check if a method call with an intended turbofish has been written without surrounding + /// angle brackets. + pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut PathSegment) { + if token::ModSep == self.token.kind && segment.args.is_none() { + let snapshot = self.clone(); + self.bump(); + let lo = self.token.span; + match self.parse_angle_args() { + Ok(args) => { + let span = lo.to(self.prev_token.span); + // Detect trailing `>` like in `x.collect::Vec<_>>()`. + let mut trailing_span = self.prev_token.span.shrink_to_hi(); + while self.token.kind == token::BinOp(token::Shr) + || self.token.kind == token::Gt + { + trailing_span = trailing_span.to(self.token.span); + self.bump(); + } + if self.token.kind == token::OpenDelim(token::Paren) { + // Recover from bad turbofish: `foo.collect::Vec<_>()`. + let args = AngleBracketedArgs { args, span }.into(); + segment.args = args; + + self.struct_span_err( + span, + "generic parameters without surrounding angle brackets", + ) + .multipart_suggestion( + "surround the type parameters with angle brackets", + vec![ + (span.shrink_to_lo(), "<".to_string()), + (trailing_span, ">".to_string()), + ], + Applicability::MachineApplicable, + ) + .emit(); + } else { + // This doesn't look like an invalid turbofish, can't recover parse state. + *self = snapshot; + } + } + Err(mut err) => { + // We could't parse generic parameters, unlikely to be a turbofish. Rely on + // generic parse error instead. + err.cancel(); + *self = snapshot; + } + } + } + } + /// 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/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 3926122606e6d..d06b172bc1484 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -909,8 +909,9 @@ impl<'a> Parser<'a> { } let fn_span_lo = self.token.span; - let segment = self.parse_path_segment(PathStyle::Expr)?; + let mut segment = self.parse_path_segment(PathStyle::Expr)?; self.check_trailing_angle_brackets(&segment, &[&token::OpenDelim(token::Paren)]); + self.check_turbofish_missing_angle_brackets(&mut segment); if self.check(&token::OpenDelim(token::Paren)) { // Method call `expr.f()` diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index 67e9b3af4a8cf..3dcefd362574b 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -387,7 +387,7 @@ impl<'a> Parser<'a> { /// Parses (possibly empty) list of generic arguments / associated item constraints, /// possibly including trailing comma. - fn parse_angle_args(&mut self) -> PResult<'a, Vec> { + pub(super) fn parse_angle_args(&mut self) -> PResult<'a, Vec> { let mut args = Vec::new(); while let Some(arg) = self.parse_angle_arg()? { args.push(arg); diff --git a/src/test/ui/suggestions/recover-missing-turbofish-surrounding-angle-braket.rs b/src/test/ui/suggestions/recover-missing-turbofish-surrounding-angle-braket.rs new file mode 100644 index 0000000000000..333dce390461c --- /dev/null +++ b/src/test/ui/suggestions/recover-missing-turbofish-surrounding-angle-braket.rs @@ -0,0 +1,10 @@ +fn main() { + let _ = vec![1, 2, 3].into_iter().collect::Vec<_>(); + //~^ ERROR generic parameters without surrounding angle brackets + let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>>>(); + //~^ ERROR generic parameters without surrounding angle brackets + let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>>(); + //~^ ERROR generic parameters without surrounding angle brackets + let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>(); + //~^ ERROR generic parameters without surrounding angle brackets +} diff --git a/src/test/ui/suggestions/recover-missing-turbofish-surrounding-angle-braket.stderr b/src/test/ui/suggestions/recover-missing-turbofish-surrounding-angle-braket.stderr new file mode 100644 index 0000000000000..981f95749d3ba --- /dev/null +++ b/src/test/ui/suggestions/recover-missing-turbofish-surrounding-angle-braket.stderr @@ -0,0 +1,46 @@ +error: generic parameters without surrounding angle brackets + --> $DIR/recover-missing-turbofish-surrounding-angle-braket.rs:2:48 + | +LL | let _ = vec![1, 2, 3].into_iter().collect::Vec<_>(); + | ^^^^^^ + | +help: surround the type parameters with angle brackets + | +LL | let _ = vec![1, 2, 3].into_iter().collect::>(); + | ^ ^ + +error: generic parameters without surrounding angle brackets + --> $DIR/recover-missing-turbofish-surrounding-angle-braket.rs:4:48 + | +LL | let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>>>(); + | ^^^^^^ + | +help: surround the type parameters with angle brackets + | +LL | let _ = vec![1, 2, 3].into_iter().collect::>(); + | ^ ^ + +error: generic parameters without surrounding angle brackets + --> $DIR/recover-missing-turbofish-surrounding-angle-braket.rs:6:48 + | +LL | let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>>(); + | ^^^^^^ + | +help: surround the type parameters with angle brackets + | +LL | let _ = vec![1, 2, 3].into_iter().collect::>(); + | ^ ^ + +error: generic parameters without surrounding angle brackets + --> $DIR/recover-missing-turbofish-surrounding-angle-braket.rs:8:48 + | +LL | let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>(); + | ^^^^^^ + | +help: surround the type parameters with angle brackets + | +LL | let _ = vec![1, 2, 3].into_iter().collect::>(); + | ^ ^ + +error: aborting due to 4 previous errors +