about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_resolve/diagnostics.rs128
-rw-r--r--src/libsyntax/parse/parser.rs8
-rw-r--r--src/test/ui/struct-literal-variant-in-if.rs14
-rw-r--r--src/test/ui/struct-literal-variant-in-if.stderr33
4 files changed, 132 insertions, 51 deletions
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 9b02f98164f..b7deb546882 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -240,6 +240,56 @@ impl<'a> Resolver<'a> {
         (err, candidates)
     }
 
+    fn followed_by_brace(&self, span: Span) -> (bool, Option<(Span, String)>) {
+        // HACK(estebank): find a better way to figure out that this was a
+        // parser issue where a struct literal is being used on an expression
+        // where a brace being opened means a block is being started. Look
+        // ahead for the next text to see if `span` is followed by a `{`.
+        let sm = self.session.source_map();
+        let mut sp = span;
+        loop {
+            sp = sm.next_point(sp);
+            match sm.span_to_snippet(sp) {
+                Ok(ref snippet) => {
+                    if snippet.chars().any(|c| { !c.is_whitespace() }) {
+                        break;
+                    }
+                }
+                _ => break,
+            }
+        }
+        let followed_by_brace = match sm.span_to_snippet(sp) {
+            Ok(ref snippet) if snippet == "{" => true,
+            _ => false,
+        };
+        // In case this could be a struct literal that needs to be surrounded
+        // by parenthesis, find the appropriate span.
+        let mut i = 0;
+        let mut closing_brace = None;
+        loop {
+            sp = sm.next_point(sp);
+            match sm.span_to_snippet(sp) {
+                Ok(ref snippet) => {
+                    if snippet == "}" {
+                        let sp = span.to(sp);
+                        if let Ok(snippet) = sm.span_to_snippet(sp) {
+                            closing_brace = Some((sp, snippet));
+                        }
+                        break;
+                    }
+                }
+                _ => break,
+            }
+            i += 1;
+            // The bigger the span, the more likely we're incorrect --
+            // bound it to 100 chars long.
+            if i > 100 {
+                break;
+            }
+        }
+        return (followed_by_brace, closing_brace)
+    }
+
     /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
     /// function.
     /// Returns `true` if able to provide context-dependent help.
@@ -278,6 +328,8 @@ impl<'a> Resolver<'a> {
             _ => false,
         };
 
+        let (followed_by_brace, closing_brace) = self.followed_by_brace(span);
+
         match (def, source) {
             (Def::Macro(..), _) => {
                 err.span_suggestion(
@@ -331,52 +383,6 @@ impl<'a> Resolver<'a> {
                         );
                     }
                 } else {
-                    // HACK(estebank): find a better way to figure out that this was a
-                    // parser issue where a struct literal is being used on an expression
-                    // where a brace being opened means a block is being started. Look
-                    // ahead for the next text to see if `span` is followed by a `{`.
-                    let sm = self.session.source_map();
-                    let mut sp = span;
-                    loop {
-                        sp = sm.next_point(sp);
-                        match sm.span_to_snippet(sp) {
-                            Ok(ref snippet) => {
-                                if snippet.chars().any(|c| { !c.is_whitespace() }) {
-                                    break;
-                                }
-                            }
-                            _ => break,
-                        }
-                    }
-                    let followed_by_brace = match sm.span_to_snippet(sp) {
-                        Ok(ref snippet) if snippet == "{" => true,
-                        _ => false,
-                    };
-                    // In case this could be a struct literal that needs to be surrounded
-                    // by parenthesis, find the appropriate span.
-                    let mut i = 0;
-                    let mut closing_brace = None;
-                    loop {
-                        sp = sm.next_point(sp);
-                        match sm.span_to_snippet(sp) {
-                            Ok(ref snippet) => {
-                                if snippet == "}" {
-                                    let sp = span.to(sp);
-                                    if let Ok(snippet) = sm.span_to_snippet(sp) {
-                                        closing_brace = Some((sp, snippet));
-                                    }
-                                    break;
-                                }
-                            }
-                            _ => break,
-                        }
-                        i += 1;
-                        // The bigger the span, the more likely we're incorrect --
-                        // bound it to 100 chars long.
-                        if i > 100 {
-                            break;
-                        }
-                    }
                     match source {
                         PathSource::Expr(Some(parent)) => if !path_sep(err, &parent) {
                             err.span_label(
@@ -411,7 +417,35 @@ impl<'a> Resolver<'a> {
             (Def::Union(..), _) |
             (Def::Variant(..), _) |
             (Def::Ctor(_, _, CtorKind::Fictive), _) if ns == ValueNS => {
-                err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?", path_str));
+                    match source {
+                        PathSource::Expr(Some(parent)) => if !path_sep(err, &parent) {
+                            err.span_label(
+                                span,
+                                format!("did you mean `{} {{ /* fields */ }}`?", path_str),
+                            );
+                        }
+                        PathSource::Expr(None) if followed_by_brace == true => {
+                            if let Some((sp, snippet)) = closing_brace {
+                                err.span_suggestion(
+                                    sp,
+                                    "surround the struct literal with parenthesis",
+                                    format!("({})", snippet),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            } else {
+                                err.span_label(
+                                    span,
+                                    format!("did you mean `({} {{ /* fields */ }})`?", path_str),
+                                );
+                            }
+                        },
+                        _ => {
+                            err.span_label(
+                                span,
+                                format!("did you mean `{} {{ /* fields */ }}`?", path_str),
+                            );
+                        },
+                    }
             }
             (Def::SelfTy(..), _) if ns == ValueNS => {
                 err.span_label(span, fallback_label);
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 7d130470c6a..a82b1e11a52 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2856,7 +2856,7 @@ impl<'a> Parser<'a> {
                         hi = self.prev_span;
                         ex = ExprKind::Mac(respan(lo.to(hi), Mac_ { path, tts, delim }));
                     } else if self.check(&token::OpenDelim(token::Brace)) {
-                        if let Some(expr) = self.should_parse_struct_expr(lo, path.clone(), attrs.clone()) {
+                        if let Some(expr) = self.should_parse_struct_expr(lo, &path, &attrs) {
                             return expr;
                         } else {
                             hi = path.span;
@@ -2907,8 +2907,8 @@ impl<'a> Parser<'a> {
     fn should_parse_struct_expr(
         &mut self,
         lo: Span,
-        path: ast::Path,
-        attrs: ThinVec<Attribute>,
+        path: &ast::Path,
+        attrs: &ThinVec<Attribute>,
     ) -> Option<PResult<'a, P<Expr>>> {
         let could_be_struct = self.look_ahead(1, |t| t.is_ident()) && (
             self.look_ahead(2, |t| *t == token::Colon)
@@ -2924,7 +2924,7 @@ impl<'a> Parser<'a> {
             parse_struct = true;
         }
         if parse_struct {
-            match self.parse_struct_expr(lo, path, attrs) {
+            match self.parse_struct_expr(lo, path.clone(), attrs.clone()) {
                 Err(err) => return Some(Err(err)),
                 Ok(expr) => {
                     if bad_struct {
diff --git a/src/test/ui/struct-literal-variant-in-if.rs b/src/test/ui/struct-literal-variant-in-if.rs
new file mode 100644
index 00000000000..2d87c4ca73d
--- /dev/null
+++ b/src/test/ui/struct-literal-variant-in-if.rs
@@ -0,0 +1,14 @@
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+enum E {
+    V { field: bool }
+}
+fn test_E(x: E) {
+    let field = true;
+    if x == E::V { field } {}
+    //~^ ERROR expected value, found struct variant `E::V`
+    //~| ERROR mismatched types
+    let y: usize = ();
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/struct-literal-variant-in-if.stderr b/src/test/ui/struct-literal-variant-in-if.stderr
new file mode 100644
index 00000000000..e38eb0d61e0
--- /dev/null
+++ b/src/test/ui/struct-literal-variant-in-if.stderr
@@ -0,0 +1,33 @@
+error[E0423]: expected value, found struct variant `E::V`
+  --> $DIR/struct-literal-variant-in-if.rs:7:13
+   |
+LL |     if x == E::V { field } {}
+   |             ^^^^----------
+   |             |
+   |             help: surround the struct literal with parenthesis: `(E::V { field })`
+
+error[E0308]: mismatched types
+  --> $DIR/struct-literal-variant-in-if.rs:7:20
+   |
+LL | fn test_E(x: E) {
+   |                 - help: try adding a return type: `-> bool`
+LL |     let field = true;
+LL |     if x == E::V { field } {}
+   |                    ^^^^^ expected (), found bool
+   |
+   = note: expected type `()`
+              found type `bool`
+
+error[E0308]: mismatched types
+  --> $DIR/struct-literal-variant-in-if.rs:10:20
+   |
+LL |     let y: usize = ();
+   |                    ^^ expected usize, found ()
+   |
+   = note: expected type `usize`
+              found type `()`
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0308, E0423.
+For more information about an error, try `rustc --explain E0308`.