]> git.lizzy.rs Git - rust.git/commitdiff
Expand suggestions for type ascription parse errors
authorEsteban Küber <esteban@kuber.com.ar>
Wed, 13 Mar 2019 02:27:10 +0000 (19:27 -0700)
committerEsteban Küber <esteban@kuber.com.ar>
Sat, 23 Mar 2019 02:50:18 +0000 (19:50 -0700)
20 files changed:
src/librustc_resolve/lib.rs
src/libsyntax/parse/parser.rs
src/test/ui/error-codes/E0423.stderr
src/test/ui/issues/issue-22644.stderr
src/test/ui/issues/issue-34255-1.rs [new file with mode: 0644]
src/test/ui/issues/issue-34255-1.stderr [new file with mode: 0644]
src/test/ui/lifetime_starts_expressions.stderr
src/test/ui/parser/struct-literal-in-for.stderr
src/test/ui/parser/struct-literal-in-if.stderr
src/test/ui/parser/struct-literal-in-while.stderr
src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr
src/test/ui/suggestions/type-ascription-instead-of-let.rs [new file with mode: 0644]
src/test/ui/suggestions/type-ascription-instead-of-let.stderr [new file with mode: 0644]
src/test/ui/suggestions/type-ascription-instead-of-method.rs [new file with mode: 0644]
src/test/ui/suggestions/type-ascription-instead-of-method.stderr [new file with mode: 0644]
src/test/ui/suggestions/type-ascription-instead-of-path.rs [new file with mode: 0644]
src/test/ui/suggestions/type-ascription-instead-of-path.stderr [new file with mode: 0644]
src/test/ui/suggestions/type-ascription-instead-of-variant.rs [new file with mode: 0644]
src/test/ui/suggestions/type-ascription-instead-of-variant.stderr [new file with mode: 0644]
src/test/ui/type/type-ascription-instead-of-statement-end.stderr

index ac149be4b2a8936929eae67f4d2b8f8865897714..1a03292290288c55f19e64ee19079009c7ebd2c2 100644 (file)
@@ -3264,11 +3264,21 @@ fn smart_resolve_path_fragment(&mut self,
         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;
@@ -3276,10 +3286,8 @@ fn type_ascription_suggestion(&self,
                 // 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");
@@ -3290,6 +3298,29 @@ fn type_ascription_suggestion(&self,
                                 ";".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,
+                                );
+                            }
+                            if let Ok(base_snippet) = base_snippet {
+                                err.span_suggestion(
+                                    base_span,
+                                    "maybe you meant to write an assignment here",
+                                    format!("let {}", base_snippet),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
                         }
                         break;
                     } else if !snippet.trim().is_empty() {
index 5627ac3fcf24545f3f0a1f9854bcc8b55c30d8d8..d052abf96d7995056d75606b82ae9401b180866a 100644 (file)
@@ -3546,22 +3546,19 @@ fn parse_assoc_expr_with(&mut self,
                 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 @@ fn parse_assoc_expr_with(&mut self,
         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>> {
index bdcfaae60a010a3b59c3fb2c31cd3c9f00da7b55..af5f88f4ce5f31d307ed9516e5fd3107ab140ded 100644 (file)
@@ -3,6 +3,19 @@ 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 expressions with a type: `<expr>: <type>`
+note: this expression is annotated with type ascription...
+  --> $DIR/E0423.rs:12:36
+   |
+LL |     if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
+   |                                    ^
+note: ...due to this, which is why a type is expected after
+  --> $DIR/E0423.rs:12:37
+   |
+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 +28,19 @@ 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 expressions with a type: `<expr>: <type>`
+note: this expression is annotated with type ascription...
+  --> $DIR/E0423.rs:21:32
+   |
+LL |     for _ in std::ops::Range { start: 0, end: 10 } {}
+   |                                ^^^^^
+note: ...due to this, which is why a type is expected after
+  --> $DIR/E0423.rs:21:37
+   |
+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
index cbff5575ed20e33afe3eda930ea4d46e35c94389..08758ce9c94587c79c24d3d48f27664e1fafd57d 100644 (file)
@@ -88,6 +88,19 @@ 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 expressions with a type: `<expr>: <type>`
+note: this expression is annotated with type ascription...
+  --> $DIR/issue-22644.rs:34:20
+   |
+LL |     println!("{}", a: &mut 4);
+   |                    ^
+note: ...due to this, which is why a type is expected after
+  --> $DIR/issue-22644.rs:34:21
+   |
+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 (file)
index 0000000..b107193
--- /dev/null
@@ -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 (file)
index 0000000..ea32430
--- /dev/null
@@ -0,0 +1,21 @@
+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 expressions with a type: `<expr>: <type>`
+note: this expression is annotated with type ascription...
+  --> $DIR/issue-34255-1.rs:8:17
+   |
+LL |     Test::Drill(field: 42);
+   |                 ^^^^^
+note: ...due to this, which is why a type is expected after
+  --> $DIR/issue-34255-1.rs:8:22
+   |
+LL |     Test::Drill(field: 42);
+   |                      ^
+   = help: this might be indicative of a syntax error elsewhere
+
+error: aborting due to previous error
+
index fa0a7ac002b2ff2eec0335544428d316ba6450fa..3de3298e3b52bd2ede0b9204e242a52d31433629 100644 (file)
@@ -13,6 +13,19 @@ 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 expressions with a type: `<expr>: <type>`
+note: this expression is annotated with type ascription...
+  --> $DIR/lifetime_starts_expressions.rs:6:12
+   |
+LL |     loop { break 'label: loop { break 'label 42; }; }
+   |            ^^^^^^^^^^^^
+note: ...due to this, which is why a type is expected after
+  --> $DIR/lifetime_starts_expressions.rs:6:24
+   |
+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
 
index b319c64f406f1da4f3bb8dd3be5c06d697fa913a..2940f465826b602cb55f404a0cfe20d79a48c83d 100644 (file)
@@ -3,6 +3,19 @@ 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 expressions with a type: `<expr>: <type>`
+note: this expression is annotated with type ascription...
+  --> $DIR/struct-literal-in-for.rs:13:9
+   |
+LL |         x: 3
+   |         ^
+note: ...due to this, which is why a type is expected after
+  --> $DIR/struct-literal-in-for.rs:13:10
+   |
+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
index 27672eeda830beedf2b501b3ac568d779f75edea..e7d22ae0292e6424d8fb8a4a8cdc205f8df7215e 100644 (file)
@@ -3,6 +3,19 @@ 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 expressions with a type: `<expr>: <type>`
+note: this expression is annotated with type ascription...
+  --> $DIR/struct-literal-in-if.rs:13:9
+   |
+LL |         x: 3
+   |         ^
+note: ...due to this, which is why a type is expected after
+  --> $DIR/struct-literal-in-if.rs:13:10
+   |
+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
index 8a130f441a3eec1ca224e53cd334590b30a5aace..038e30956ff5389e17a10ceb0849660aef1b5107 100644 (file)
@@ -3,6 +3,19 @@ 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 expressions with a type: `<expr>: <type>`
+note: this expression is annotated with type ascription...
+  --> $DIR/struct-literal-in-while.rs:13:9
+   |
+LL |         x: 3
+   |         ^
+note: ...due to this, which is why a type is expected after
+  --> $DIR/struct-literal-in-while.rs:13:10
+   |
+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
index 3505d00b64b76599446fe0a01a225ec4e656fe45..b3a6f6ac734839e4d66229d076dacc314649378d 100644 (file)
@@ -3,6 +3,19 @@ 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 expressions with a type: `<expr>: <type>`
+note: this expression is annotated with type ascription...
+  --> $DIR/struct-literal-restrictions-in-lamda.rs:13:9
+   |
+LL |         x: 3
+   |         ^
+note: ...due to this, which is why a type is expected after
+  --> $DIR/struct-literal-restrictions-in-lamda.rs:13:10
+   |
+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 (file)
index 0000000..51d3d32
--- /dev/null
@@ -0,0 +1,11 @@
+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
+        //~| ERROR type ascription is experimental
+        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 (file)
index 0000000..1efa94a
--- /dev/null
@@ -0,0 +1,28 @@
+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
+   |         expecting a type here because of type ascription
+   |         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:8:9
+   |
+LL |         temp + value + 1
+   |         ^^^^ not found in this scope
+
+error[E0658]: type ascription is experimental (see issue #23416)
+  --> $DIR/type-ascription-instead-of-let.rs:5:9
+   |
+LL |         temp: i32 = fun(5i32);
+   |         ^^^^^^^^^
+   |
+   = help: add #![feature(type_ascription)] to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0425, E0658.
+For more information about an 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 (file)
index 0000000..361729d
--- /dev/null
@@ -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 (file)
index 0000000..15ec087
--- /dev/null
@@ -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 (file)
index 0000000..a81996e
--- /dev/null
@@ -0,0 +1,6 @@
+fn main() {
+    std:io::stdin();
+    //~^ ERROR failed to resolve: use of undeclared type or module `io`
+    //~| ERROR expected value, found module
+    //~| ERROR type ascription is experimental
+}
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 (file)
index 0000000..e371611
--- /dev/null
@@ -0,0 +1,35 @@
+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();
+   |     ^^^
+   |     |
+   |     not a value
+   |     expecting a type here because of type ascription
+help: maybe you meant to write a path separator here
+   |
+LL |     std::io::stdin();
+   |        ^^
+help: maybe you meant to write an assignment here
+   |
+LL |     let std:io::stdin();
+   |     ^^^^^^^
+
+error[E0658]: type ascription is experimental (see issue #23416)
+  --> $DIR/type-ascription-instead-of-path.rs:2:5
+   |
+LL |     std:io::stdin();
+   |     ^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(type_ascription)] to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0423, E0433, E0658.
+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 (file)
index 0000000..b90867f
--- /dev/null
@@ -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 (file)
index 0000000..5719a66
--- /dev/null
@@ -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
+
index bc5a923a3f32fc43ab866e61d6a1ba1028c27d1f..4077be9d08280e09cfb5a51e4bddec8c34161855 100644 (file)
@@ -11,6 +11,19 @@ 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 expressions with a type: `<expr>: <type>`
+note: this expression is annotated with type ascription...
+  --> $DIR/type-ascription-instead-of-statement-end.rs:9:5
+   |
+LL |     println!("test"): 0;
+   |     ^^^^^^^^^^^^^^^^
+note: ...due to this, which is why a type is expected after
+  --> $DIR/type-ascription-instead-of-statement-end.rs:9:21
+   |
+LL |     println!("test"): 0;
+   |                     ^
+   = help: this might be indicative of a syntax error elsewhere
 
 error: aborting due to 2 previous errors