about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-08-09 19:50:03 +0000
committerbors <bors@rust-lang.org>2017-08-09 19:50:03 +0000
commitf142499539d038ef60f4e22cafe11ecdd8a29a1d (patch)
tree0a0dbb8de48b38587afcc77e43a5d837e629d127
parent33d71944cd359db9d90718abe37559d419070eb9 (diff)
parent9bd62a4691346a30f7aa26cf3b6d726695cf7eee (diff)
downloadrust-f142499539d038ef60f4e22cafe11ecdd8a29a1d.tar.gz
rust-f142499539d038ef60f4e22cafe11ecdd8a29a1d.zip
Auto merge of #43484 - estebank:point-to-return, r=arielb1
Point at return type always when type mismatch against it

Before this, the diagnostic errors would only point at the return type
when changing it would be a possible solution to a type error. Add a
label to the return type without a suggestion to change in order to make
the source of the expected type obvious.

Follow up to #42850, fixes #25133, fixes #41897.
-rw-r--r--src/librustc/ty/mod.rs1
-rw-r--r--src/librustc_typeck/check/mod.rs61
-rw-r--r--src/test/compile-fail/struct-path-self-type-mismatch.rs12
-rw-r--r--src/test/ui/block-result/block-must-not-have-result-res.stderr2
-rw-r--r--src/test/ui/block-result/issue-13624.stderr2
-rw-r--r--src/test/ui/block-result/issue-22645.stderr3
-rw-r--r--src/test/ui/block-result/issue-5500.stderr2
-rw-r--r--src/test/ui/mismatched_types/abridged.stderr14
8 files changed, 71 insertions, 26 deletions
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 7f4aedb5f14..b44fb982f8a 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -491,6 +491,7 @@ impl<'tcx> TyS<'tcx> {
             TypeVariants::TyFnPtr(..) |
             TypeVariants::TyDynamic(..) |
             TypeVariants::TyClosure(..) |
+            TypeVariants::TyInfer(..) |
             TypeVariants::TyProjection(..) => false,
             _ => true,
         }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index e53e5e7b08c..2181906fc8b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4229,8 +4229,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         ty
     }
 
-    /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether it is
-    /// `fn main` if it is a method, `None` otherwise.
+    /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether a
+    /// suggetion can be made, `None` otherwise.
     pub fn get_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, bool)> {
         // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
         // `while` before reaching it, as block tail returns are not available in them.
@@ -4241,9 +4241,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 name, node: hir::ItemFn(ref decl, ..), ..
             }) = parent {
                 decl.clone().and_then(|decl| {
-                    // This is less than ideal, it will not present the return type span on any
-                    // method called `main`, regardless of whether it is actually the entry point.
-                    Some((decl, name == Symbol::intern("main")))
+                    // This is less than ideal, it will not suggest a return type span on any
+                    // method called `main`, regardless of whether it is actually the entry point,
+                    // but it will still present it as the reason for the expected type.
+                    Some((decl, name != Symbol::intern("main")))
                 })
             } else if let Node::NodeTraitItem(&hir::TraitItem {
                 node: hir::TraitItemKind::Method(hir::MethodSig {
@@ -4251,6 +4252,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }, ..), ..
             }) = parent {
                 decl.clone().and_then(|decl| {
+                    Some((decl, true))
+                })
+            } else if let Node::NodeImplItem(&hir::ImplItem {
+                node: hir::ImplItemKind::Method(hir::MethodSig {
+                    ref decl, ..
+                }, ..), ..
+            }) = parent {
+                decl.clone().and_then(|decl| {
                     Some((decl, false))
                 })
             } else {
@@ -4275,11 +4284,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                             blk_id: ast::NodeId) {
         self.suggest_missing_semicolon(err, expression, expected, cause_span);
 
-        if let Some((fn_decl, is_main)) = self.get_fn_decl(blk_id) {
-            // `fn main()` must return `()`, do not suggest changing return type
-            if !is_main {
-                self.suggest_missing_return_type(err, &fn_decl, found);
-            }
+        if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
+            self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
         }
     }
 
@@ -4335,20 +4341,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     fn suggest_missing_return_type(&self,
                                    err: &mut DiagnosticBuilder<'tcx>,
                                    fn_decl: &hir::FnDecl,
-                                   ty: Ty<'tcx>) {
-
-        // Only recommend changing the return type for methods that
+                                   expected: Ty<'tcx>,
+                                   found: Ty<'tcx>,
+                                   can_suggest: bool) {
+        // Only suggest changing the return type for methods that
         // haven't set a return type at all (and aren't `fn main()` or an impl).
-        if let &hir::FnDecl {
-            output: hir::FunctionRetTy::DefaultReturn(span), ..
-        } = fn_decl {
-            if ty.is_suggestable() {
+        match (&fn_decl.output, found.is_suggestable(), can_suggest) {
+            (&hir::FunctionRetTy::DefaultReturn(span), true, true) => {
                 err.span_suggestion(span,
                                     "try adding a return type",
-                                    format!("-> {} ", ty));
-            } else {
+                                    format!("-> {} ", found));
+            }
+            (&hir::FunctionRetTy::DefaultReturn(span), false, true) => {
                 err.span_label(span, "possibly return type missing here?");
             }
+            (&hir::FunctionRetTy::DefaultReturn(span), _, _) => {
+                // `fn main()` must return `()`, do not suggest changing return type
+                err.span_label(span, "expected `()` because of default return type");
+            }
+            (&hir::FunctionRetTy::Return(ref ty), _, _) => {
+                // Only point to return type if the expected type is the return type, as if they
+                // are not, the expectation must have been caused by something else.
+                debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.node);
+                let sp = ty.span;
+                let ty = AstConv::ast_ty_to_ty(self, ty);
+                debug!("suggest_missing_return_type: return type sty {:?}", ty.sty);
+                debug!("suggest_missing_return_type: expected type sty {:?}", ty.sty);
+                if ty.sty == expected.sty {
+                    err.span_label(sp, format!("expected `{}` because of return type",
+                                               expected));
+                }
+            }
         }
     }
 
diff --git a/src/test/compile-fail/struct-path-self-type-mismatch.rs b/src/test/compile-fail/struct-path-self-type-mismatch.rs
index f694e7d277c..ad568b41fcb 100644
--- a/src/test/compile-fail/struct-path-self-type-mismatch.rs
+++ b/src/test/compile-fail/struct-path-self-type-mismatch.rs
@@ -20,17 +20,15 @@ impl Bar for Foo<i32> {
 }
 
 impl<T> Foo<T> {
-    fn new<U>(u: U) -> Foo<U> {
+    fn new<U>(u: U) -> Foo<U> { //~ NOTE expected `Foo<U>` because of return type
         Self {
         //~^ ERROR mismatched types
-        //~| expected type parameter, found a different type parameter
-        //~| expected type `Foo<U>`
-        //~| found type `Foo<T>`
+        //~| NOTE expected type parameter, found a different type parameter
+        //~| NOTE expected type `Foo<U>`
             inner: u
             //~^ ERROR mismatched types
-            //~| expected type parameter, found a different type parameter
-            //~| expected type `T`
-            //~| found type `U`
+            //~| NOTE expected type parameter, found a different type parameter
+            //~| NOTE expected type `T`
         }
     }
 }
diff --git a/src/test/ui/block-result/block-must-not-have-result-res.stderr b/src/test/ui/block-result/block-must-not-have-result-res.stderr
index f60a0c2e5f6..20c7dc416f3 100644
--- a/src/test/ui/block-result/block-must-not-have-result-res.stderr
+++ b/src/test/ui/block-result/block-must-not-have-result-res.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/block-must-not-have-result-res.rs:15:9
    |
+14 |     fn drop(&mut self) {
+   |                        - expected `()` because of default return type
 15 |         true //~  ERROR mismatched types
    |         ^^^^ expected (), found bool
    |
diff --git a/src/test/ui/block-result/issue-13624.stderr b/src/test/ui/block-result/issue-13624.stderr
index 41113eb7a57..cd8c28cd2cf 100644
--- a/src/test/ui/block-result/issue-13624.stderr
+++ b/src/test/ui/block-result/issue-13624.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/issue-13624.rs:17:5
    |
+16 |   pub fn get_enum_struct_variant() -> () {
+   |                                       -- expected `()` because of return type
 17 |     Enum::EnumStructVariant { x: 1, y: 2, z: 3 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `a::Enum`
    |
diff --git a/src/test/ui/block-result/issue-22645.stderr b/src/test/ui/block-result/issue-22645.stderr
index a9bcc8bea94..c6113ae0c9f 100644
--- a/src/test/ui/block-result/issue-22645.stderr
+++ b/src/test/ui/block-result/issue-22645.stderr
@@ -11,6 +11,9 @@ error[E0277]: the trait bound `{integer}: Scalar` is not satisfied
 error[E0308]: mismatched types
   --> $DIR/issue-22645.rs:25:3
    |
+23 | fn main() {
+   |           - expected `()` because of default return type
+24 |   let b = Bob + 3.5;
 25 |   b + 3 //~ ERROR E0277
    |   ^^^^^ expected (), found struct `Bob`
    |
diff --git a/src/test/ui/block-result/issue-5500.stderr b/src/test/ui/block-result/issue-5500.stderr
index bd670a14f24..29dbd5a8cf5 100644
--- a/src/test/ui/block-result/issue-5500.stderr
+++ b/src/test/ui/block-result/issue-5500.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/issue-5500.rs:12:5
    |
+11 | fn main() {
+   |           - expected `()` because of default return type
 12 |     &panic!()
    |     ^^^^^^^^^ expected (), found reference
    |
diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr
index d40bc3b3339..8c63d7d6f91 100644
--- a/src/test/ui/mismatched_types/abridged.stderr
+++ b/src/test/ui/mismatched_types/abridged.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/abridged.rs:26:5
    |
+25 | fn a() -> Foo {
+   |           --- expected `Foo` because of return type
 26 |     Some(Foo { bar: 1 })
    |     ^^^^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::option::Option`
    |
@@ -10,6 +12,8 @@ error[E0308]: mismatched types
 error[E0308]: mismatched types
   --> $DIR/abridged.rs:30:5
    |
+29 | fn a2() -> Foo {
+   |            --- expected `Foo` because of return type
 30 |     Ok(Foo { bar: 1})
    |     ^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::result::Result`
    |
@@ -19,6 +23,8 @@ error[E0308]: mismatched types
 error[E0308]: mismatched types
   --> $DIR/abridged.rs:34:5
    |
+33 | fn b() -> Option<Foo> {
+   |           ----------- expected `std::option::Option<Foo>` because of return type
 34 |     Foo { bar: 1 }
    |     ^^^^^^^^^^^^^^ expected enum `std::option::Option`, found struct `Foo`
    |
@@ -28,6 +34,8 @@ error[E0308]: mismatched types
 error[E0308]: mismatched types
   --> $DIR/abridged.rs:38:5
    |
+37 | fn c() -> Result<Foo, Bar> {
+   |           ---------------- expected `std::result::Result<Foo, Bar>` because of return type
 38 |     Foo { bar: 1 }
    |     ^^^^^^^^^^^^^^ expected enum `std::result::Result`, found struct `Foo`
    |
@@ -37,6 +45,9 @@ error[E0308]: mismatched types
 error[E0308]: mismatched types
   --> $DIR/abridged.rs:49:5
    |
+41 | fn d() -> X<X<String, String>, String> {
+   |           ---------------------------- expected `X<X<std::string::String, std::string::String>, std::string::String>` because of return type
+...
 49 |     x
    |     ^ expected struct `std::string::String`, found integral variable
    |
@@ -46,6 +57,9 @@ error[E0308]: mismatched types
 error[E0308]: mismatched types
   --> $DIR/abridged.rs:60:5
    |
+52 | fn e() -> X<X<String, String>, String> {
+   |           ---------------------------- expected `X<X<std::string::String, std::string::String>, std::string::String>` because of return type
+...
 60 |     x
    |     ^ expected struct `std::string::String`, found integral variable
    |