about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-03-26 09:05:39 +0100
committerGitHub <noreply@github.com>2019-03-26 09:05:39 +0100
commitb316514dbd716d7885cb5d5f4be43e3b63441b49 (patch)
treebefdb4bb9eea756a2cfe7ffb8d6477ed689a0365
parent54479c624cc24bb852291d83e11cc19389dcb21b (diff)
parentd72ef21ddd4d56b3ec169a5ed64fa4cbf778c5c8 (diff)
downloadrust-b316514dbd716d7885cb5d5f4be43e3b63441b49.tar.gz
rust-b316514dbd716d7885cb5d5f4be43e3b63441b49.zip
Rollup merge of #59150 - estebank:type-ascription, r=varkor
Expand suggestions for type ascription parse errors

Fix #51222. CC #48016, #47666, #54516, #34255.
-rw-r--r--src/librustc_resolve/lib.rs64
-rw-r--r--src/libsyntax/feature_gate.rs8
-rw-r--r--src/libsyntax/parse/parser.rs75
-rw-r--r--src/test/ui/error-codes/E0423.stderr16
-rw-r--r--src/test/ui/issues/issue-22644.stderr8
-rw-r--r--src/test/ui/issues/issue-34255-1.rs10
-rw-r--r--src/test/ui/issues/issue-34255-1.stderr16
-rw-r--r--src/test/ui/lifetime_starts_expressions.stderr8
-rw-r--r--src/test/ui/parser/struct-literal-in-for.stderr8
-rw-r--r--src/test/ui/parser/struct-literal-in-if.stderr8
-rw-r--r--src/test/ui/parser/struct-literal-in-while.stderr8
-rw-r--r--src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr8
-rw-r--r--src/test/ui/suggestions/type-ascription-instead-of-let.rs10
-rw-r--r--src/test/ui/suggestions/type-ascription-instead-of-let.stderr18
-rw-r--r--src/test/ui/suggestions/type-ascription-instead-of-method.rs4
-rw-r--r--src/test/ui/suggestions/type-ascription-instead-of-method.stderr10
-rw-r--r--src/test/ui/suggestions/type-ascription-instead-of-path.rs5
-rw-r--r--src/test/ui/suggestions/type-ascription-instead-of-path.stderr18
-rw-r--r--src/test/ui/suggestions/type-ascription-instead-of-variant.rs4
-rw-r--r--src/test/ui/suggestions/type-ascription-instead-of-variant.stderr10
-rw-r--r--src/test/ui/type/type-ascription-instead-of-statement-end.stderr8
21 files changed, 302 insertions, 22 deletions
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 2be76cb6b44..f48cfa0b147 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -3262,11 +3262,21 @@ impl<'a> Resolver<'a> {
         resolution
     }
 
-    fn type_ascription_suggestion(&self,
-                                  err: &mut DiagnosticBuilder<'_>,
-                                  base_span: Span) {
+    /// Only used in a specific case of type ascription suggestions
+    #[doc(hidden)]
+    fn get_colon_suggestion_span(&self, start: Span) -> Span {
+        let cm = self.session.source_map();
+        start.to(cm.next_point(start))
+    }
+
+    fn type_ascription_suggestion(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        base_span: Span,
+    ) {
         debug!("type_ascription_suggetion {:?}", base_span);
         let cm = self.session.source_map();
+        let base_snippet = cm.span_to_snippet(base_span);
         debug!("self.current_type_ascription {:?}", self.current_type_ascription);
         if let Some(sp) = self.current_type_ascription.last() {
             let mut sp = *sp;
@@ -3274,13 +3284,10 @@ impl<'a> Resolver<'a> {
                 // Try to find the `:`; bail on first non-':' / non-whitespace.
                 sp = cm.next_point(sp);
                 if let Ok(snippet) = cm.span_to_snippet(sp.to(cm.next_point(sp))) {
-                    debug!("snippet {:?}", snippet);
                     let line_sp = cm.lookup_char_pos(sp.hi()).line;
                     let line_base_sp = cm.lookup_char_pos(base_span.lo()).line;
-                    debug!("{:?} {:?}", line_sp, line_base_sp);
                     if snippet == ":" {
-                        err.span_label(base_span,
-                                       "expecting a type here because of type ascription");
+                        let mut show_label = true;
                         if line_sp != line_base_sp {
                             err.span_suggestion_short(
                                 sp,
@@ -3288,6 +3295,49 @@ impl<'a> Resolver<'a> {
                                 ";".to_string(),
                                 Applicability::MaybeIncorrect,
                             );
+                        } else {
+                            let colon_sp = self.get_colon_suggestion_span(sp);
+                            let after_colon_sp = self.get_colon_suggestion_span(
+                                colon_sp.shrink_to_hi(),
+                            );
+                            if !cm.span_to_snippet(after_colon_sp).map(|s| s == " ")
+                                .unwrap_or(false)
+                            {
+                                err.span_suggestion(
+                                    colon_sp,
+                                    "maybe you meant to write a path separator here",
+                                    "::".to_string(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                                show_label = false;
+                            }
+                            if let Ok(base_snippet) = base_snippet {
+                                let mut sp = after_colon_sp;
+                                for _ in 0..100 {
+                                    // Try to find an assignment
+                                    sp = cm.next_point(sp);
+                                    let snippet = cm.span_to_snippet(sp.to(cm.next_point(sp)));
+                                    match snippet {
+                                        Ok(ref x) if x.as_str() == "=" => {
+                                            err.span_suggestion(
+                                                base_span,
+                                                "maybe you meant to write an assignment here",
+                                                format!("let {}", base_snippet),
+                                                Applicability::MaybeIncorrect,
+                                            );
+                                            show_label = false;
+                                            break;
+                                        }
+                                        Ok(ref x) if x.as_str() == "\n" => break,
+                                        Err(_) => break,
+                                        Ok(_) => {}
+                                    }
+                                }
+                            }
+                        }
+                        if show_label {
+                            err.span_label(base_span,
+                                           "expecting a type here because of type ascription");
                         }
                         break;
                     } else if !snippet.trim().is_empty() {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index d1d0d79a705..96c89d3176a 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -1836,8 +1836,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
             }
             ast::ExprKind::Type(..) => {
-                gate_feature_post!(&self, type_ascription, e.span,
-                                  "type ascription is experimental");
+                // To avoid noise about type ascription in common syntax errors, only emit if it
+                // is the *only* error.
+                if self.context.parse_sess.span_diagnostic.err_count() == 0 {
+                    gate_feature_post!(&self, type_ascription, e.span,
+                                       "type ascription is experimental");
+                }
             }
             ast::ExprKind::ObsoleteInPlace(..) => {
                 // these get a hard error in ast-validation
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index d7a2170342d..a0c3fe35608 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3538,22 +3538,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);
                     }
                 };
@@ -3658,6 +3655,58 @@ 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 an expression with a type: `<expr>: <type>`");
+                err.span_note(
+                    lhs_span,
+                    "this expression expects an ascribed type after the colon",
+                );
+                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>> {
diff --git a/src/test/ui/error-codes/E0423.stderr b/src/test/ui/error-codes/E0423.stderr
index bdcfaae60a0..b0ef4e1b254 100644
--- a/src/test/ui/error-codes/E0423.stderr
+++ b/src/test/ui/error-codes/E0423.stderr
@@ -3,6 +3,14 @@ error: expected type, found `1`
    |
 LL |     if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
    |                                       ^ expecting a type here because of type ascription
+   |
+   = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+note: this expression expects an ascribed type after the colon
+  --> $DIR/E0423.rs:12:36
+   |
+LL |     if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
+   |                                    ^
+   = help: this might be indicative of a syntax error elsewhere
 
 error: expected expression, found `==`
   --> $DIR/E0423.rs:15:13
@@ -15,6 +23,14 @@ error: expected type, found `0`
    |
 LL |     for _ in std::ops::Range { start: 0, end: 10 } {}
    |                                       ^ expecting a type here because of type ascription
+   |
+   = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+note: this expression expects an ascribed type after the colon
+  --> $DIR/E0423.rs:21:32
+   |
+LL |     for _ in std::ops::Range { start: 0, end: 10 } {}
+   |                                ^^^^^
+   = help: this might be indicative of a syntax error elsewhere
 
 error[E0423]: expected function, found struct `Foo`
   --> $DIR/E0423.rs:4:13
diff --git a/src/test/ui/issues/issue-22644.stderr b/src/test/ui/issues/issue-22644.stderr
index cbff5575ed2..a28ea0d09f8 100644
--- a/src/test/ui/issues/issue-22644.stderr
+++ b/src/test/ui/issues/issue-22644.stderr
@@ -88,6 +88,14 @@ error: expected type, found `4`
    |
 LL |     println!("{}", a: &mut 4);
    |                            ^ expecting a type here because of type ascription
+   |
+   = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+note: this expression expects an ascribed type after the colon
+  --> $DIR/issue-22644.rs:34:20
+   |
+LL |     println!("{}", a: &mut 4);
+   |                    ^
+   = help: this might be indicative of a syntax error elsewhere
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/issues/issue-34255-1.rs b/src/test/ui/issues/issue-34255-1.rs
new file mode 100644
index 00000000000..b1071934bb2
--- /dev/null
+++ b/src/test/ui/issues/issue-34255-1.rs
@@ -0,0 +1,10 @@
+enum Test {
+    Drill {
+        field: i32,
+    }
+}
+
+fn main() {
+    Test::Drill(field: 42);
+    //~^ ERROR expected type, found
+}
diff --git a/src/test/ui/issues/issue-34255-1.stderr b/src/test/ui/issues/issue-34255-1.stderr
new file mode 100644
index 00000000000..7899c8d30f1
--- /dev/null
+++ b/src/test/ui/issues/issue-34255-1.stderr
@@ -0,0 +1,16 @@
+error: expected type, found `42`
+  --> $DIR/issue-34255-1.rs:8:24
+   |
+LL |     Test::Drill(field: 42);
+   |                        ^^ expecting a type here because of type ascription
+   |
+   = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+note: this expression expects an ascribed type after the colon
+  --> $DIR/issue-34255-1.rs:8:17
+   |
+LL |     Test::Drill(field: 42);
+   |                 ^^^^^
+   = help: this might be indicative of a syntax error elsewhere
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetime_starts_expressions.stderr b/src/test/ui/lifetime_starts_expressions.stderr
index fa0a7ac002b..cb5a52a3e08 100644
--- a/src/test/ui/lifetime_starts_expressions.stderr
+++ b/src/test/ui/lifetime_starts_expressions.stderr
@@ -13,6 +13,14 @@ error: expected type, found keyword `loop`
    |
 LL |     loop { break 'label: loop { break 'label 42; }; }
    |                          ^^^^ expecting a type here because of type ascription
+   |
+   = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+note: this expression expects an ascribed type after the colon
+  --> $DIR/lifetime_starts_expressions.rs:6:12
+   |
+LL |     loop { break 'label: loop { break 'label 42; }; }
+   |            ^^^^^^^^^^^^
+   = help: this might be indicative of a syntax error elsewhere
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/parser/struct-literal-in-for.stderr b/src/test/ui/parser/struct-literal-in-for.stderr
index b319c64f406..07f2e41ac4f 100644
--- a/src/test/ui/parser/struct-literal-in-for.stderr
+++ b/src/test/ui/parser/struct-literal-in-for.stderr
@@ -3,6 +3,14 @@ error: expected type, found `3`
    |
 LL |         x: 3
    |            ^ expecting a type here because of type ascription
+   |
+   = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+note: this expression expects an ascribed type after the colon
+  --> $DIR/struct-literal-in-for.rs:13:9
+   |
+LL |         x: 3
+   |         ^
+   = help: this might be indicative of a syntax error elsewhere
 
 error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
   --> $DIR/struct-literal-in-for.rs:14:12
diff --git a/src/test/ui/parser/struct-literal-in-if.stderr b/src/test/ui/parser/struct-literal-in-if.stderr
index 27672eeda83..3dd61e74f12 100644
--- a/src/test/ui/parser/struct-literal-in-if.stderr
+++ b/src/test/ui/parser/struct-literal-in-if.stderr
@@ -3,6 +3,14 @@ error: expected type, found `3`
    |
 LL |         x: 3
    |            ^ expecting a type here because of type ascription
+   |
+   = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+note: this expression expects an ascribed type after the colon
+  --> $DIR/struct-literal-in-if.rs:13:9
+   |
+LL |         x: 3
+   |         ^
+   = help: this might be indicative of a syntax error elsewhere
 
 error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
   --> $DIR/struct-literal-in-if.rs:14:12
diff --git a/src/test/ui/parser/struct-literal-in-while.stderr b/src/test/ui/parser/struct-literal-in-while.stderr
index 8a130f441a3..d48244654cd 100644
--- a/src/test/ui/parser/struct-literal-in-while.stderr
+++ b/src/test/ui/parser/struct-literal-in-while.stderr
@@ -3,6 +3,14 @@ error: expected type, found `3`
    |
 LL |         x: 3
    |            ^ expecting a type here because of type ascription
+   |
+   = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+note: this expression expects an ascribed type after the colon
+  --> $DIR/struct-literal-in-while.rs:13:9
+   |
+LL |         x: 3
+   |         ^
+   = help: this might be indicative of a syntax error elsewhere
 
 error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
   --> $DIR/struct-literal-in-while.rs:14:12
diff --git a/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr b/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr
index 3505d00b64b..a8c93233dbc 100644
--- a/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr
+++ b/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr
@@ -3,6 +3,14 @@ error: expected type, found `3`
    |
 LL |         x: 3
    |            ^ expecting a type here because of type ascription
+   |
+   = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+note: this expression expects an ascribed type after the colon
+  --> $DIR/struct-literal-restrictions-in-lamda.rs:13:9
+   |
+LL |         x: 3
+   |         ^
+   = help: this might be indicative of a syntax error elsewhere
 
 error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
   --> $DIR/struct-literal-restrictions-in-lamda.rs:14:12
diff --git a/src/test/ui/suggestions/type-ascription-instead-of-let.rs b/src/test/ui/suggestions/type-ascription-instead-of-let.rs
new file mode 100644
index 00000000000..0e1c3075027
--- /dev/null
+++ b/src/test/ui/suggestions/type-ascription-instead-of-let.rs
@@ -0,0 +1,10 @@
+fn fun(x: i32) -> i32 { x }
+
+fn main() {
+    let closure_annotated = |value: i32| -> i32 {
+        temp: i32 = fun(5i32);
+        //~^ ERROR cannot find value `temp` in this scope
+        temp + value + 1
+        //~^ ERROR cannot find value `temp` in this scope
+    };
+}
diff --git a/src/test/ui/suggestions/type-ascription-instead-of-let.stderr b/src/test/ui/suggestions/type-ascription-instead-of-let.stderr
new file mode 100644
index 00000000000..92e4b5798c8
--- /dev/null
+++ b/src/test/ui/suggestions/type-ascription-instead-of-let.stderr
@@ -0,0 +1,18 @@
+error[E0425]: cannot find value `temp` in this scope
+  --> $DIR/type-ascription-instead-of-let.rs:5:9
+   |
+LL |         temp: i32 = fun(5i32);
+   |         ^^^^
+   |         |
+   |         not found in this scope
+   |         help: maybe you meant to write an assignment here: `let temp`
+
+error[E0425]: cannot find value `temp` in this scope
+  --> $DIR/type-ascription-instead-of-let.rs:7:9
+   |
+LL |         temp + value + 1
+   |         ^^^^ not found in this scope
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/suggestions/type-ascription-instead-of-method.rs b/src/test/ui/suggestions/type-ascription-instead-of-method.rs
new file mode 100644
index 00000000000..361729d50c2
--- /dev/null
+++ b/src/test/ui/suggestions/type-ascription-instead-of-method.rs
@@ -0,0 +1,4 @@
+fn main() {
+    Box:new("foo".to_string())
+    //~^ ERROR expected type, found
+}
diff --git a/src/test/ui/suggestions/type-ascription-instead-of-method.stderr b/src/test/ui/suggestions/type-ascription-instead-of-method.stderr
new file mode 100644
index 00000000000..15ec087b1cc
--- /dev/null
+++ b/src/test/ui/suggestions/type-ascription-instead-of-method.stderr
@@ -0,0 +1,10 @@
+error: expected type, found `"foo"`
+  --> $DIR/type-ascription-instead-of-method.rs:2:13
+   |
+LL |     Box:new("foo".to_string())
+   |        -    ^^^^^ expecting a type here because of type ascription
+   |        |
+   |        help: maybe you meant to write a path separator here: `::`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path.rs b/src/test/ui/suggestions/type-ascription-instead-of-path.rs
new file mode 100644
index 00000000000..4c0fe6d8b5b
--- /dev/null
+++ b/src/test/ui/suggestions/type-ascription-instead-of-path.rs
@@ -0,0 +1,5 @@
+fn main() {
+    std:io::stdin();
+    //~^ ERROR failed to resolve: use of undeclared type or module `io`
+    //~| ERROR expected value, found module
+}
diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path.stderr b/src/test/ui/suggestions/type-ascription-instead-of-path.stderr
new file mode 100644
index 00000000000..1beb822d6a7
--- /dev/null
+++ b/src/test/ui/suggestions/type-ascription-instead-of-path.stderr
@@ -0,0 +1,18 @@
+error[E0433]: failed to resolve: use of undeclared type or module `io`
+  --> $DIR/type-ascription-instead-of-path.rs:2:9
+   |
+LL |     std:io::stdin();
+   |         ^^ use of undeclared type or module `io`
+
+error[E0423]: expected value, found module `std`
+  --> $DIR/type-ascription-instead-of-path.rs:2:5
+   |
+LL |     std:io::stdin();
+   |     ^^^- help: maybe you meant to write a path separator here: `::`
+   |     |
+   |     not a value
+
+error: aborting due to 2 previous errors
+
+Some errors occurred: E0423, E0433.
+For more information about an error, try `rustc --explain E0423`.
diff --git a/src/test/ui/suggestions/type-ascription-instead-of-variant.rs b/src/test/ui/suggestions/type-ascription-instead-of-variant.rs
new file mode 100644
index 00000000000..b90867fef6b
--- /dev/null
+++ b/src/test/ui/suggestions/type-ascription-instead-of-variant.rs
@@ -0,0 +1,4 @@
+fn main() {
+    let _ = Option:Some("");
+    //~^ ERROR expected type, found
+}
diff --git a/src/test/ui/suggestions/type-ascription-instead-of-variant.stderr b/src/test/ui/suggestions/type-ascription-instead-of-variant.stderr
new file mode 100644
index 00000000000..5719a667a84
--- /dev/null
+++ b/src/test/ui/suggestions/type-ascription-instead-of-variant.stderr
@@ -0,0 +1,10 @@
+error: expected type, found `""`
+  --> $DIR/type-ascription-instead-of-variant.rs:2:25
+   |
+LL |     let _ = Option:Some("");
+   |                   -     ^^ expecting a type here because of type ascription
+   |                   |
+   |                   help: maybe you meant to write a path separator here: `::`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type/type-ascription-instead-of-statement-end.stderr b/src/test/ui/type/type-ascription-instead-of-statement-end.stderr
index bc5a923a3f3..2084cbcce4f 100644
--- a/src/test/ui/type/type-ascription-instead-of-statement-end.stderr
+++ b/src/test/ui/type/type-ascription-instead-of-statement-end.stderr
@@ -11,6 +11,14 @@ error: expected type, found `0`
    |
 LL |     println!("test"): 0;
    |                       ^ expecting a type here because of type ascription
+   |
+   = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+note: this expression expects an ascribed type after the colon
+  --> $DIR/type-ascription-instead-of-statement-end.rs:9:5
+   |
+LL |     println!("test"): 0;
+   |     ^^^^^^^^^^^^^^^^
+   = help: this might be indicative of a syntax error elsewhere
 
 error: aborting due to 2 previous errors