about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2017-12-17 01:53:11 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2017-12-17 19:00:50 +0300
commit70e5c3731961b5754bc5b155a75b2f7ff7fb997b (patch)
tree0ec785acdd6d1c3ffe94041151b4514424d15e43 /src/libsyntax/parse
parentaf57acef1cd1651861be0bfe77b4f4dd3066ce02 (diff)
downloadrust-70e5c3731961b5754bc5b155a75b2f7ff7fb997b.tar.gz
rust-70e5c3731961b5754bc5b155a75b2f7ff7fb997b.zip
syntax: recovery for incorrect associated item paths like `[T; N]::clone`
Diffstat (limited to 'src/libsyntax/parse')
-rw-r--r--src/libsyntax/parse/parser.rs70
1 files changed, 50 insertions, 20 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 09a65046e20..c3dd17e8775 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -169,6 +169,13 @@ enum PrevTokenKind {
     Other,
 }
 
+pub(crate) trait RecoverQPath: Sized {
+    fn to_ty(&self) -> Option<P<Ty>>;
+    fn to_recovered(&self, qself: Option<QSelf>, path: ast::Path) -> Self;
+    fn to_string(&self) -> String;
+    const PATH_STYLE: PathStyle = PathStyle::Expr;
+}
+
 /* ident is handled by common.rs */
 
 #[derive(Clone)]
@@ -1567,6 +1574,7 @@ impl<'a> Parser<'a> {
 
         // Try to recover from use of `+` with incorrect priority.
         self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
+        let ty = self.maybe_recover_from_bad_qpath(ty)?;
 
         Ok(P(ty))
     }
@@ -1621,6 +1629,32 @@ impl<'a> Parser<'a> {
         Ok(())
     }
 
+    // Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`.
+    fn maybe_recover_from_bad_qpath<T: RecoverQPath>(&mut self, base: T) -> PResult<'a, T> {
+        // Do not add `::` to expected tokens.
+        if self.token != token::ModSep {
+            return Ok(base);
+        }
+        let ty = match base.to_ty() {
+            Some(ty) => ty,
+            None => return Ok(base),
+        };
+
+        self.bump(); // `::`
+        let mut segments = Vec::new();
+        self.parse_path_segments(&mut segments, T::PATH_STYLE, true)?;
+
+        let span = ty.span.to(self.prev_span);
+        let recovered =
+            base.to_recovered(Some(QSelf { ty, position: 0 }), ast::Path { segments, span });
+
+        self.diagnostic()
+            .struct_span_err(span, "missing angle brackets in associated item path")
+            .span_suggestion(span, "try", recovered.to_string()).emit();
+
+        Ok(recovered)
+    }
+
     fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
         let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
         let mutbl = self.parse_mutability();
@@ -2012,12 +2046,7 @@ impl<'a> Parser<'a> {
     }
 
     pub fn mk_expr(&mut self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> {
-        P(Expr {
-            id: ast::DUMMY_NODE_ID,
-            node,
-            span,
-            attrs: attrs.into(),
-        })
+        P(Expr { node, span, attrs, id: ast::DUMMY_NODE_ID })
     }
 
     pub fn mk_unary(&mut self, unop: ast::UnOp, expr: P<Expr>) -> ast::ExprKind {
@@ -2139,12 +2168,11 @@ impl<'a> Parser<'a> {
                 self.bump();
 
                 hi = self.prev_span;
-                let span = lo.to(hi);
-                return if es.len() == 1 && !trailing_comma {
-                    Ok(self.mk_expr(span, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs))
+                ex = if es.len() == 1 && !trailing_comma {
+                    ExprKind::Paren(es.into_iter().nth(0).unwrap())
                 } else {
-                    Ok(self.mk_expr(span, ExprKind::Tup(es), attrs))
-                }
+                    ExprKind::Tup(es)
+                };
             }
             token::OpenDelim(token::Brace) => {
                 return self.parse_block_expr(lo, BlockCheckMode::Default, attrs);
@@ -2344,7 +2372,10 @@ impl<'a> Parser<'a> {
             }
         }
 
-        return Ok(self.mk_expr(lo.to(hi), ex, attrs));
+        let expr = Expr { node: ex, span: lo.to(hi), id: ast::DUMMY_NODE_ID, attrs };
+        let expr = self.maybe_recover_from_bad_qpath(expr)?;
+
+        return Ok(P(expr));
     }
 
     fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec<Attribute>)
@@ -3405,7 +3436,7 @@ impl<'a> Parser<'a> {
 
                     if self.check(&token::Comma) ||
                             self.check(&token::CloseDelim(token::Bracket)) {
-                        slice = Some(P(ast::Pat {
+                        slice = Some(P(Pat {
                             id: ast::DUMMY_NODE_ID,
                             node: PatKind::Wild,
                             span: self.span,
@@ -3492,14 +3523,14 @@ impl<'a> Parser<'a> {
                     (false, false) => BindingMode::ByValue(Mutability::Immutable),
                 };
                 let fieldpath = codemap::Spanned{span:self.prev_span, node:fieldname};
-                let fieldpat = P(ast::Pat{
+                let fieldpat = P(Pat {
                     id: ast::DUMMY_NODE_ID,
                     node: PatKind::Ident(bind_type, fieldpath, None),
                     span: boxed_span.to(hi),
                 });
 
                 let subpat = if is_box {
-                    P(ast::Pat{
+                    P(Pat {
                         id: ast::DUMMY_NODE_ID,
                         node: PatKind::Box(fieldpat),
                         span: lo.to(hi),
@@ -3708,11 +3739,10 @@ impl<'a> Parser<'a> {
             }
         }
 
-        Ok(P(ast::Pat {
-            id: ast::DUMMY_NODE_ID,
-            node: pat,
-            span: lo.to(self.prev_span),
-        }))
+        let pat = Pat { node: pat, span: lo.to(self.prev_span), id: ast::DUMMY_NODE_ID };
+        let pat = self.maybe_recover_from_bad_qpath(pat)?;
+
+        Ok(P(pat))
     }
 
     /// Parse ident or ident @ pat