about summary refs log tree commit diff
path: root/src/librustc_parse/parser
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2020-07-23 09:34:07 -0700
committerEsteban Küber <esteban@kuber.com.ar>2020-07-23 09:35:49 -0700
commit20f4e5d9c24809031fd6631436f0a7a5b075fe40 (patch)
tree04ec2b6aa9813e7c3561310ca0e999d8838e6174 /src/librustc_parse/parser
parent9e92106d457abd14f82adc29e7f2496861e07916 (diff)
downloadrust-20f4e5d9c24809031fd6631436f0a7a5b075fe40.tar.gz
rust-20f4e5d9c24809031fd6631436f0a7a5b075fe40.zip
Detect turbofish missing surrounding angle brackets
Diffstat (limited to 'src/librustc_parse/parser')
-rw-r--r--src/librustc_parse/parser/diagnostics.rs42
-rw-r--r--src/librustc_parse/parser/expr.rs3
-rw-r--r--src/librustc_parse/parser/path.rs2
3 files changed, 44 insertions, 3 deletions
diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs
index 3244b35e89b..f84f54054ac 100644
--- a/src/librustc_parse/parser/diagnostics.rs
+++ b/src/librustc_parse/parser/diagnostics.rs
@@ -2,7 +2,9 @@ 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::{
+    AngleBracketedArgs, AttrVec, ItemKind, Mutability, 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,44 @@ 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) if self.token.kind == token::OpenDelim(token::Paren) => {
+                    // Recover from bad turbofish: `foo.collect::Vec<_>()`.
+                    let span = lo.to(self.prev_token.span);
+                    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()),
+                            (span.shrink_to_hi(), ">".to_string()),
+                        ],
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+                }
+                Ok(_) => {
+                    *self = snapshot;
+                }
+                Err(mut err) => {
+                    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 3926122606e..d06b172bc14 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 67e9b3af4a8..3dcefd36257 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<AngleBracketedArg>> {
+    pub(super) fn parse_angle_args(&mut self) -> PResult<'a, Vec<AngleBracketedArg>> {
         let mut args = Vec::new();
         while let Some(arg) = self.parse_angle_arg()? {
             args.push(arg);