about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2020-06-22 12:28:16 -0700
committerEsteban Küber <esteban@kuber.com.ar>2020-06-22 15:20:04 -0700
commitf84b7e1b052fd135ae2e754499b4fe286d5ba699 (patch)
treec8c910bf3359b602588affd5be512d2b1da68a2f
parenta39c7787ba246353178e099373b9240be0d9e603 (diff)
downloadrust-f84b7e1b052fd135ae2e754499b4fe286d5ba699.tar.gz
rust-f84b7e1b052fd135ae2e754499b4fe286d5ba699.zip
Provide context on E0308 involving fn items
-rw-r--r--src/librustc_infer/infer/error_reporting/mod.rs2
-rw-r--r--src/librustc_typeck/check/demand.rs1
-rw-r--r--src/librustc_typeck/check/mod.rs42
-rw-r--r--src/test/ui/fn/fn-item-type.rs34
-rw-r--r--src/test/ui/fn/fn-item-type.stderr31
5 files changed, 99 insertions, 11 deletions
diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs
index 9cfa11dd7c8..7fdcbd31df3 100644
--- a/src/librustc_infer/infer/error_reporting/mod.rs
+++ b/src/librustc_infer/infer/error_reporting/mod.rs
@@ -1256,7 +1256,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             (ty::FnDef(did1, substs1), ty::FnPtr(sig2)) => {
                 let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
                 let mut values = self.cmp_fn_sig(&sig1, sig2);
-                values.0.push_normal(format!(
+                values.0.push_highlighted(format!(
                     " {{{}}}",
                     self.tcx.def_path_str_with_substs(*did1, substs1)
                 ));
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 019b4ca6606..f4f630e94a7 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -34,6 +34,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
         self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
         self.suggest_missing_await(err, expr, expected, expr_ty);
+        self.note_need_for_fn_pointer(err, expected, expr_ty);
     }
 
     // Requires that the two types unify, and prints an error message if
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index b60b06567d6..234a573b725 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -5496,6 +5496,48 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    fn note_need_for_fn_pointer(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        match (&expected.kind, &found.kind) {
+            (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
+                let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
+                let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2);
+                if sig1 != sig2 {
+                    return;
+                }
+                err.note(
+                    "different `fn` items always have unique types, even if their signatures are \
+                     the same",
+                );
+                err.help(&format!("change the expectation to require function pointer `{}`", sig1));
+                err.help(&format!(
+                    "if the expectation is due to type inference, cast the expected `fn` to a \
+                     function pointer: `{} as {}`",
+                    self.tcx.def_path_str_with_substs(*did1, substs1),
+                    sig1
+                ));
+            }
+            (ty::FnDef(did, substs), ty::FnPtr(sig2)) => {
+                let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs);
+                if sig1 != *sig2 {
+                    return;
+                }
+                err.help(&format!("change the expectation to require function pointer `{}`", sig1));
+                err.help(&format!(
+                    "if the expectation is due to type inference, cast the expected `fn` to a \
+                     function pointer: `{} as {}`",
+                    self.tcx.def_path_str_with_substs(*did, substs),
+                    sig1
+                ));
+            }
+            _ => {}
+        }
+    }
+
     /// A common error is to add an extra semicolon:
     ///
     /// ```
diff --git a/src/test/ui/fn/fn-item-type.rs b/src/test/ui/fn/fn-item-type.rs
index 68b75c18a43..256b9d45755 100644
--- a/src/test/ui/fn/fn-item-type.rs
+++ b/src/test/ui/fn/fn-item-type.rs
@@ -12,22 +12,44 @@ impl<T> Foo for T { /* `foo` is still default here */ }
 fn main() {
     eq(foo::<u8>, bar::<u8>);
     //~^ ERROR mismatched types
-    //~|  expected fn item `fn(_) -> _ {foo::<u8>}`
-    //~|  found fn item `fn(_) -> _ {bar::<u8>}`
-    //~|  expected fn item, found a different fn item
+    //~| expected fn item `fn(_) -> _ {foo::<u8>}`
+    //~| found fn item `fn(_) -> _ {bar::<u8>}`
+    //~| expected fn item, found a different fn item
+    //~| different `fn` items always have unique types, even if their signatures are the same
+    //~| change the expectation to require function pointer
+    //~| if the expectation is due to type inference, cast the expected `fn` to a function pointer
 
     eq(foo::<u8>, foo::<i8>);
     //~^ ERROR mismatched types
     //~| expected `u8`, found `i8`
+    //~| different `fn` items always have unique types, even if their signatures are the same
+    //~| change the expectation to require function pointer
+    //~| if the expectation is due to type inference, cast the expected `fn` to a function pointer
 
     eq(bar::<String>, bar::<Vec<u8>>);
     //~^ ERROR mismatched types
-    //~|  expected fn item `fn(_) -> _ {bar::<std::string::String>}`
-    //~|  found fn item `fn(_) -> _ {bar::<std::vec::Vec<u8>>}`
-    //~|  expected struct `std::string::String`, found struct `std::vec::Vec`
+    //~| expected fn item `fn(_) -> _ {bar::<std::string::String>}`
+    //~| found fn item `fn(_) -> _ {bar::<std::vec::Vec<u8>>}`
+    //~| expected struct `std::string::String`, found struct `std::vec::Vec`
+    //~| different `fn` items always have unique types, even if their signatures are the same
+    //~| change the expectation to require function pointer
+    //~| if the expectation is due to type inference, cast the expected `fn` to a function pointer
 
     // Make sure we distinguish between trait methods correctly.
     eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
     //~^ ERROR mismatched types
     //~| expected `u8`, found `u16`
+    //~| different `fn` items always have unique types, even if their signatures are the same
+    //~| change the expectation to require function pointer
+    //~| if the expectation is due to type inference, cast the expected `fn` to a function pointer
+
+    eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
+    //~^ ERROR mismatched types
+    //~| expected fn item `fn(_) -> _ {foo::<u8>}`
+    //~| found fn pointer `fn(_) -> _`
+    //~| expected fn item, found fn pointer
+    //~| change the expectation to require function pointer
+    //~| if the expectation is due to type inference, cast the expected `fn` to a function pointer
+
+    eq(foo::<u8> as fn(isize) -> isize, bar::<u8>); // ok!
 }
diff --git a/src/test/ui/fn/fn-item-type.stderr b/src/test/ui/fn/fn-item-type.stderr
index 4cce25c43c4..84f5e034340 100644
--- a/src/test/ui/fn/fn-item-type.stderr
+++ b/src/test/ui/fn/fn-item-type.stderr
@@ -6,34 +6,57 @@ LL |     eq(foo::<u8>, bar::<u8>);
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
               found fn item `fn(_) -> _ {bar::<u8>}`
+   = note: different `fn` items always have unique types, even if their signatures are the same
+   = help: change the expectation to require function pointer `fn(isize) -> isize`
+   = help: if the expectation is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
 
 error[E0308]: mismatched types
-  --> $DIR/fn-item-type.rs:19:19
+  --> $DIR/fn-item-type.rs:22:19
    |
 LL |     eq(foo::<u8>, foo::<i8>);
    |                   ^^^^^^^^^ expected `u8`, found `i8`
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
               found fn item `fn(_) -> _ {foo::<i8>}`
+   = note: different `fn` items always have unique types, even if their signatures are the same
+   = help: change the expectation to require function pointer `fn(isize) -> isize`
+   = help: if the expectation is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
 
 error[E0308]: mismatched types
-  --> $DIR/fn-item-type.rs:23:23
+  --> $DIR/fn-item-type.rs:29:23
    |
 LL |     eq(bar::<String>, bar::<Vec<u8>>);
    |                       ^^^^^^^^^^^^^^ expected struct `std::string::String`, found struct `std::vec::Vec`
    |
    = note: expected fn item `fn(_) -> _ {bar::<std::string::String>}`
               found fn item `fn(_) -> _ {bar::<std::vec::Vec<u8>>}`
+   = note: different `fn` items always have unique types, even if their signatures are the same
+   = help: change the expectation to require function pointer `fn(isize) -> isize`
+   = help: if the expectation is due to type inference, cast the expected `fn` to a function pointer: `bar::<std::string::String> as fn(isize) -> isize`
 
 error[E0308]: mismatched types
-  --> $DIR/fn-item-type.rs:30:26
+  --> $DIR/fn-item-type.rs:39:26
    |
 LL |     eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
    |                          ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
    |
    = note: expected fn item `fn() {<u8 as Foo>::foo}`
               found fn item `fn() {<u16 as Foo>::foo}`
+   = note: different `fn` items always have unique types, even if their signatures are the same
+   = help: change the expectation to require function pointer `fn()`
+   = help: if the expectation is due to type inference, cast the expected `fn` to a function pointer: `<u8 as Foo>::foo as fn()`
 
-error: aborting due to 4 previous errors
+error[E0308]: mismatched types
+  --> $DIR/fn-item-type.rs:46:19
+   |
+LL |     eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
+   |
+   = note: expected fn item `fn(_) -> _ {foo::<u8>}`
+           found fn pointer `fn(_) -> _`
+   = help: change the expectation to require function pointer `fn(isize) -> isize`
+   = help: if the expectation is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0308`.