about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-07-25 18:16:43 +0000
committerbors <bors@rust-lang.org>2020-07-25 18:16:43 +0000
commitf06e8e157cc86538eacb76a65073787b0e46c396 (patch)
tree4de463d2a0462ff402fc61c688c2a4b50cbd1aca
parentfe08fb7b1e7cc5ef45e107f05b3cd30d48313d2b (diff)
parentd090e5ed3327a24c17754be7e224b5f2345aa622 (diff)
downloadrust-f06e8e157cc86538eacb76a65073787b0e46c396.tar.gz
rust-f06e8e157cc86538eacb76a65073787b0e46c396.zip
Auto merge of #74687 - estebank:bracketless-turbofish, r=matthewjasper
Detect turbofish missing surrounding angle brackets

Fix #74065.
-rw-r--r--src/librustc_parse/parser/diagnostics.rs57
-rw-r--r--src/librustc_parse/parser/expr.rs3
-rw-r--r--src/librustc_parse/parser/path.rs2
-rw-r--r--src/test/ui/suggestions/recover-missing-turbofish-surrounding-angle-braket.rs10
-rw-r--r--src/test/ui/suggestions/recover-missing-turbofish-surrounding-angle-braket.stderr46
5 files changed, 114 insertions, 4 deletions
diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs
index 3244b35e89b..609a0c961e9 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 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);
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 00000000000..333dce39046
--- /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 00000000000..981f95749d3
--- /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::<Vec<_>>();
+   |                                                ^      ^
+
+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::<Vec<_>>();
+   |                                                ^      ^
+
+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::<Vec<_>>();
+   |                                                ^      ^
+
+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::<Vec<_>>();
+   |                                                ^      ^
+
+error: aborting due to 4 previous errors
+