]> git.lizzy.rs Git - rust.git/commitdiff
Improve display of error E0308 for structs
authorJosh Leeb-du Toit <josh.leebdutoit@gmail.com>
Sat, 28 Oct 2017 23:44:05 +0000 (10:44 +1100)
committerJosh Leeb-du Toit <josh.leebdutoit@gmail.com>
Tue, 31 Oct 2017 23:21:26 +0000 (10:21 +1100)
Improve the display of error E0308 for structs by adding a "did you
mean" span label.

src/librustc/infer/error_reporting/mod.rs
src/test/ui/issue-35241.rs [new file with mode: 0644]
src/test/ui/issue-35241.stderr [new file with mode: 0644]

index 895894a0bb2fc5ee1613f0d97ad2f6475ebb82db..aac67b528c2d08d3b6a2b28d21d8a38c4bc407e1 100644 (file)
@@ -66,7 +66,7 @@
 use hir::def_id::DefId;
 use middle::region;
 use traits::{ObligationCause, ObligationCauseCode};
-use ty::{self, Region, Ty, TyCtxt, TypeFoldable};
+use ty::{self, Region, Ty, TyCtxt, TypeFoldable, TypeVariants};
 use ty::error::TypeError;
 use syntax::ast::DUMMY_NODE_ID;
 use syntax_pos::{Pos, Span};
@@ -673,14 +673,17 @@ pub fn note_type_err(&self,
                          values: Option<ValuePairs<'tcx>>,
                          terr: &TypeError<'tcx>)
     {
-        let (expected_found, is_simple_error) = match values {
-            None => (None, false),
+        let (expected_found, exp_found, is_simple_error) = match values {
+            None => (None, None, false),
             Some(values) => {
-                let is_simple_error = match values {
+                let (is_simple_error, exp_found) = match values {
                     ValuePairs::Types(exp_found) => {
-                        exp_found.expected.is_primitive() && exp_found.found.is_primitive()
+                        let is_simple_err = exp_found.expected.is_primitive()
+                            && exp_found.found.is_primitive();
+
+                        (is_simple_err, Some(exp_found))
                     }
-                    _ => false,
+                    _ => (false, None),
                 };
                 let vals = match self.values_str(&values) {
                     Some((expected, found)) => Some((expected, found)),
@@ -690,12 +693,17 @@ pub fn note_type_err(&self,
                         return
                     }
                 };
-                (vals, is_simple_error)
+                (vals, exp_found, is_simple_error)
             }
         };
 
         let span = cause.span;
 
+        diag.span_label(span, terr.to_string());
+        if let Some((sp, msg)) = secondary_span {
+            diag.span_label(sp, msg);
+        }
+
         if let Some((expected, found)) = expected_found {
             match (terr, is_simple_error, expected == found) {
                 (&TypeError::Sorts(ref values), false, true) => {
@@ -704,18 +712,37 @@ pub fn note_type_err(&self,
                         &format!(" ({})", values.expected.sort_string(self.tcx)),
                         &format!(" ({})", values.found.sort_string(self.tcx)));
                 }
-                (_, false,  _) => {
+                (_, false, _) => {
+                    if let Some(exp_found) = exp_found {
+                        let (def_id, ret_ty) = match exp_found.found.sty {
+                            TypeVariants::TyFnDef(def, _) => {
+                                (Some(def), Some(self.tcx.fn_sig(def).output()))
+                            }
+                            _ => (None, None)
+                        };
+
+                        let exp_is_struct = match exp_found.expected.sty {
+                            TypeVariants::TyAdt(def, _) => def.is_struct(),
+                            _ => false
+                        };
+
+                        if let (Some(def_id), Some(ret_ty)) = (def_id, ret_ty) {
+                            if exp_is_struct && exp_found.expected == ret_ty.0 {
+                                let message = format!(
+                                    "did you mean `{}(/* fields */)`?",
+                                    self.tcx.item_path_str(def_id)
+                                );
+                                diag.span_label(cause.span, message);
+                            }
+                        }
+                    }
+
                     diag.note_expected_found(&"type", expected, found);
                 }
                 _ => (),
             }
         }
 
-        diag.span_label(span, terr.to_string());
-        if let Some((sp, msg)) = secondary_span {
-            diag.span_label(sp, msg);
-        }
-
         self.note_error_origin(diag, &cause);
         self.check_and_note_conflicting_crates(diag, terr, span);
         self.tcx.note_and_explain_type_err(diag, terr, span);
diff --git a/src/test/ui/issue-35241.rs b/src/test/ui/issue-35241.rs
new file mode 100644 (file)
index 0000000..7ec3974
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo(u32);
+
+fn test() -> Foo { Foo }
+
+fn main() {}
diff --git a/src/test/ui/issue-35241.stderr b/src/test/ui/issue-35241.stderr
new file mode 100644 (file)
index 0000000..bb1bba1
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-35241.rs:13:20
+   |
+13 | fn test() -> Foo { Foo }
+   |              ---   ^^^
+   |              |     |
+   |              |     expected struct `Foo`, found fn item
+   |              |     did you mean `Foo(/* fields */)`?
+   |              expected `Foo` because of return type
+   |
+   = note: expected type `Foo`
+              found type `fn(u32) -> Foo {Foo::{{constructor}}}`
+
+error: aborting due to previous error
+