about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2019-03-12 19:27:10 -0700
committerEsteban Küber <esteban@kuber.com.ar>2019-03-22 19:50:18 -0700
commit8ba1a97e375451f51d0657e2135d4e6e657fd72e (patch)
tree30437bf238625c71e970e9a8944220148fc58b3c /src/libsyntax
parent9f91bee03f3eea93285330354dda54706028671c (diff)
downloadrust-8ba1a97e375451f51d0657e2135d4e6e657fd72e.tar.gz
rust-8ba1a97e375451f51d0657e2135d4e6e657fd72e.zip
Expand suggestions for type ascription parse errors
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/parse/parser.rs79
1 files changed, 66 insertions, 13 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 5627ac3fcf2..d052abf96d7 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3546,22 +3546,19 @@ impl<'a> Parser<'a> {
                 lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?;
                 continue
             } else if op == AssocOp::Colon {
+                let maybe_path = self.could_ascription_be_path(&lhs.node);
+                let next_sp = self.span;
+
                 lhs = match self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Type) {
                     Ok(lhs) => lhs,
                     Err(mut err) => {
-                        err.span_label(self.span,
-                                       "expecting a type here because of type ascription");
-                        let cm = self.sess.source_map();
-                        let cur_pos = cm.lookup_char_pos(self.span.lo());
-                        let op_pos = cm.lookup_char_pos(cur_op_span.hi());
-                        if cur_pos.line != op_pos.line {
-                            err.span_suggestion(
-                                cur_op_span,
-                                "try using a semicolon",
-                                ";".to_string(),
-                                Applicability::MaybeIncorrect // speculative
-                            );
-                        }
+                        self.bad_type_ascription(
+                            &mut err,
+                            lhs_span,
+                            cur_op_span,
+                            next_sp,
+                            maybe_path,
+                        );
                         return Err(err);
                     }
                 };
@@ -3666,6 +3663,62 @@ impl<'a> Parser<'a> {
         Ok(lhs)
     }
 
+    fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool {
+        self.token.is_ident() &&
+            if let ast::ExprKind::Path(..) = node { true } else { false } &&
+            !self.token.is_reserved_ident() &&           // v `foo:bar(baz)`
+            self.look_ahead(1, |t| t == &token::OpenDelim(token::Paren)) ||
+            self.look_ahead(1, |t| t == &token::Lt) &&     // `foo:bar<baz`
+            self.look_ahead(2, |t| t.is_ident()) ||
+            self.look_ahead(1, |t| t == &token::Colon) &&  // `foo:bar:baz`
+            self.look_ahead(2, |t| t.is_ident()) ||
+            self.look_ahead(1, |t| t == &token::ModSep) &&  // `foo:bar::baz`
+            self.look_ahead(2, |t| t.is_ident())
+    }
+
+    fn bad_type_ascription(
+        &self,
+        err: &mut DiagnosticBuilder<'a>,
+        lhs_span: Span,
+        cur_op_span: Span,
+        next_sp: Span,
+        maybe_path: bool,
+    ) {
+        err.span_label(self.span, "expecting a type here because of type ascription");
+        let cm = self.sess.source_map();
+        let next_pos = cm.lookup_char_pos(next_sp.lo());
+        let op_pos = cm.lookup_char_pos(cur_op_span.hi());
+        if op_pos.line != next_pos.line {
+            err.span_suggestion(
+                cur_op_span,
+                "try using a semicolon",
+                ";".to_string(),
+                Applicability::MaybeIncorrect,
+            );
+        } else {
+            if maybe_path {
+                err.span_suggestion(
+                    cur_op_span,
+                    "maybe you meant to write a path separator here",
+                    "::".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            } else {
+                err.note("type ascription is a nightly only feature that lets \
+                            you annotate expressions with a type: `<expr>: <type>`");
+                err.span_note(
+                    lhs_span,
+                    "this expression is annotated with type ascription...",
+                );
+                err.span_note(
+                    cur_op_span,
+                    "...due to this, which is why a type is expected after",
+                );
+                err.help("this might be indicative of a syntax error elsewhere");
+            }
+        }
+    }
+
     fn parse_assoc_op_cast(&mut self, lhs: P<Expr>, lhs_span: Span,
                            expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind)
                            -> PResult<'a, P<Expr>> {