about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-07-30 09:41:19 +0000
committerMichael Goulet <michael@errs.io>2022-08-16 01:21:11 +0000
commit8b64988575d4b71616620bd78d9c2e9a4f526232 (patch)
treef952d4c28b93b1e29015c00389e4c770f64df516
parent40336865fe7d4a01139a3336639c6971647e885c (diff)
downloadrust-8b64988575d4b71616620bd78d9c2e9a4f526232.tar.gz
rust-8b64988575d4b71616620bd78d9c2e9a4f526232.zip
Fix error message with non-tupled bare fn trait
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs1
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs12
-rw-r--r--compiler/rustc_middle/src/ty/error.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs30
-rw-r--r--src/test/ui/mismatched_types/E0631.rs4
-rw-r--r--src/test/ui/mismatched_types/E0631.stderr24
-rw-r--r--src/test/ui/mismatched_types/closure-arg-count.rs4
-rw-r--r--src/test/ui/mismatched_types/closure-arg-count.stderr27
-rw-r--r--src/test/ui/unboxed-closures/non-tupled-arg-mismatch.rs8
-rw-r--r--src/test/ui/unboxed-closures/non-tupled-arg-mismatch.stderr17
10 files changed, 101 insertions, 38 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index fcb87a9f32f..3c7dac2bfd8 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1750,6 +1750,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values
             && let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind()
             && let Some(def_id) = def_id.as_local()
+            && terr.involves_regions()
         {
             let span = self.tcx.def_span(def_id);
             diag.span_note(span, "this closure does not fulfill the lifetime requirements");
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 1e26e7bb86e..444817f396e 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1935,6 +1935,18 @@ impl<'tcx> TypeTrace<'tcx> {
         }
     }
 
+    pub fn poly_trait_refs(
+        cause: &ObligationCause<'tcx>,
+        a_is_expected: bool,
+        a: ty::PolyTraitRef<'tcx>,
+        b: ty::PolyTraitRef<'tcx>,
+    ) -> TypeTrace<'tcx> {
+        TypeTrace {
+            cause: cause.clone(),
+            values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+        }
+    }
+
     pub fn consts(
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 8e6af936ded..ac89bec702e 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -74,6 +74,18 @@ pub enum TypeError<'tcx> {
     TargetFeatureCast(DefId),
 }
 
+impl TypeError<'_> {
+    pub fn involves_regions(self) -> bool {
+        match self {
+            TypeError::RegionsDoesNotOutlive(_, _)
+            | TypeError::RegionsInsufficientlyPolymorphic(_, _)
+            | TypeError::RegionsOverlyPolymorphic(_, _)
+            | TypeError::RegionsPlaceholderMismatch => true,
+            _ => false,
+        }
+    }
+}
+
 /// Explains the source of a type err in a short, human readable way. This is meant to be placed
 /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
 /// afterwards to present additional details, particularly when it comes to lifetime-related
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 4260cb53adc..1a39a168038 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -22,6 +22,7 @@ use rustc_hir::intravisit::Visitor;
 use rustc_hir::GenericParam;
 use rustc_hir::Item;
 use rustc_hir::Node;
+use rustc_infer::infer::TypeTrace;
 use rustc_infer::traits::TraitEngine;
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
@@ -941,9 +942,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 
                 self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
 
+                let mut not_tupled = false;
+
                 let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() {
                     ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
-                    _ => vec![ArgKind::empty()],
+                    _ => {
+                        not_tupled = true;
+                        vec![ArgKind::empty()]
+                    }
                 };
 
                 let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
@@ -951,10 +957,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     ty::Tuple(ref tys) => {
                         tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect()
                     }
-                    _ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())],
+                    _ => {
+                        not_tupled = true;
+                        vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())]
+                    }
                 };
 
-                if found.len() == expected.len() {
+                // If this is a `Fn` family trait and either the expected or found
+                // is not tupled, then fall back to just a regular mismatch error.
+                // This shouldn't be common unless manually implementing one of the
+                // traits manually, but don't make it more confusing when it does
+                // happen.
+                if Some(expected_trait_ref.def_id()) != tcx.lang_items().gen_trait() && not_tupled {
+                    self.report_and_explain_type_error(
+                        TypeTrace::poly_trait_refs(
+                            &obligation.cause,
+                            true,
+                            expected_trait_ref,
+                            found_trait_ref,
+                        ),
+                        ty::error::TypeError::Mismatch,
+                    )
+                } else if found.len() == expected.len() {
                     self.report_closure_arg_mismatch(
                         span,
                         found_span,
diff --git a/src/test/ui/mismatched_types/E0631.rs b/src/test/ui/mismatched_types/E0631.rs
index a2939465830..e66ef6aaeda 100644
--- a/src/test/ui/mismatched_types/E0631.rs
+++ b/src/test/ui/mismatched_types/E0631.rs
@@ -5,7 +5,7 @@ fn bar<F: Fn<usize>>(_: F) {}
 fn main() {
     fn f(_: u64) {}
     foo(|_: isize| {}); //~ ERROR type mismatch
-    bar(|_: isize| {}); //~ ERROR type mismatch
+    bar(|_: isize| {}); //~ ERROR mismatched types
     foo(f); //~ ERROR type mismatch
-    bar(f); //~ ERROR type mismatch
+    bar(f); //~ ERROR mismatched types
 }
diff --git a/src/test/ui/mismatched_types/E0631.stderr b/src/test/ui/mismatched_types/E0631.stderr
index 4d673d45559..fefb6fea4eb 100644
--- a/src/test/ui/mismatched_types/E0631.stderr
+++ b/src/test/ui/mismatched_types/E0631.stderr
@@ -14,16 +14,14 @@ note: required by a bound in `foo`
 LL | fn foo<F: Fn(usize)>(_: F) {}
    |           ^^^^^^^^^ required by this bound in `foo`
 
-error[E0631]: type mismatch in closure arguments
+error[E0308]: mismatched types
   --> $DIR/E0631.rs:8:5
    |
 LL |     bar(|_: isize| {});
-   |     ^^^ ---------- found signature defined here
-   |     |
-   |     expected due to this
+   |     ^^^ types differ
    |
-   = note: expected closure signature `fn(usize) -> _`
-              found closure signature `fn(isize) -> _`
+   = note: expected trait `Fn<usize>`
+              found trait `Fn<(isize,)>`
 note: required by a bound in `bar`
   --> $DIR/E0631.rs:4:11
    |
@@ -49,19 +47,16 @@ note: required by a bound in `foo`
 LL | fn foo<F: Fn(usize)>(_: F) {}
    |           ^^^^^^^^^ required by this bound in `foo`
 
-error[E0631]: type mismatch in function arguments
+error[E0308]: mismatched types
   --> $DIR/E0631.rs:10:9
    |
-LL |     fn f(_: u64) {}
-   |     ------------ found signature defined here
-...
 LL |     bar(f);
-   |     --- ^ expected due to this
+   |     --- ^ types differ
    |     |
    |     required by a bound introduced by this call
    |
-   = note: expected function signature `fn(usize) -> _`
-              found function signature `fn(u64) -> _`
+   = note: expected trait `Fn<usize>`
+              found trait `Fn<(u64,)>`
 note: required by a bound in `bar`
   --> $DIR/E0631.rs:4:11
    |
@@ -70,4 +65,5 @@ LL | fn bar<F: Fn<usize>>(_: F) {}
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0631`.
+Some errors have detailed explanations: E0308, E0631.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/mismatched_types/closure-arg-count.rs b/src/test/ui/mismatched_types/closure-arg-count.rs
index e817631ad5d..b6759d750c8 100644
--- a/src/test/ui/mismatched_types/closure-arg-count.rs
+++ b/src/test/ui/mismatched_types/closure-arg-count.rs
@@ -11,9 +11,9 @@ fn main() {
     [1, 2, 3].sort_by(|(tuple, tuple2): (usize, _)| panic!());
     //~^ ERROR closure is expected to take
     f(|| panic!());
-    //~^ ERROR closure is expected to take
+    //~^ ERROR mismatched types
     f(  move    || panic!());
-    //~^ ERROR closure is expected to take
+    //~^ ERROR mismatched types
 
     let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i);
     //~^ ERROR closure is expected to take
diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr
index 3968774e357..d13e5d682da 100644
--- a/src/test/ui/mismatched_types/closure-arg-count.stderr
+++ b/src/test/ui/mismatched_types/closure-arg-count.stderr
@@ -45,41 +45,33 @@ help: change the closure to take multiple arguments instead of a single tuple
 LL |     [1, 2, 3].sort_by(|tuple, tuple2| panic!());
    |                       ~~~~~~~~~~~~~~~
 
-error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments
+error[E0308]: mismatched types
   --> $DIR/closure-arg-count.rs:13:5
    |
 LL |     f(|| panic!());
-   |     ^ -- takes 0 arguments
-   |     |
-   |     expected closure that takes 1 argument
+   |     ^ types differ
    |
+   = note: expected trait `Fn<usize>`
+              found trait `Fn<()>`
 note: required by a bound in `f`
   --> $DIR/closure-arg-count.rs:3:9
    |
 LL | fn f<F: Fn<usize>>(_: F) {}
    |         ^^^^^^^^^ required by this bound in `f`
-help: consider changing the closure to take and ignore the expected argument
-   |
-LL |     f(|_| panic!());
-   |       ~~~
 
-error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments
+error[E0308]: mismatched types
   --> $DIR/closure-arg-count.rs:15:5
    |
 LL |     f(  move    || panic!());
-   |     ^   ---------- takes 0 arguments
-   |     |
-   |     expected closure that takes 1 argument
+   |     ^ types differ
    |
+   = note: expected trait `Fn<usize>`
+              found trait `Fn<()>`
 note: required by a bound in `f`
   --> $DIR/closure-arg-count.rs:3:9
    |
 LL | fn f<F: Fn<usize>>(_: F) {}
    |         ^^^^^^^^^ required by this bound in `f`
-help: consider changing the closure to take and ignore the expected argument
-   |
-LL |     f(  move    |_| panic!());
-   |                 ~~~
 
 error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments
   --> $DIR/closure-arg-count.rs:18:53
@@ -198,4 +190,5 @@ LL | fn call<F, R>(_: F) where F: FnOnce() -> R {}
 
 error: aborting due to 14 previous errors
 
-For more information about this error, try `rustc --explain E0593`.
+Some errors have detailed explanations: E0308, E0593.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.rs b/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.rs
new file mode 100644
index 00000000000..925463d6dee
--- /dev/null
+++ b/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.rs
@@ -0,0 +1,8 @@
+#![feature(unboxed_closures)]
+
+fn a<F: Fn<usize>>(f: F) {}
+
+fn main() {
+    a(|_: usize| {});
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.stderr b/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.stderr
new file mode 100644
index 00000000000..9a24fb8c2be
--- /dev/null
+++ b/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.stderr
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+  --> $DIR/non-tupled-arg-mismatch.rs:6:5
+   |
+LL |     a(|_: usize| {});
+   |     ^ types differ
+   |
+   = note: expected trait `Fn<usize>`
+              found trait `Fn<(usize,)>`
+note: required by a bound in `a`
+  --> $DIR/non-tupled-arg-mismatch.rs:3:9
+   |
+LL | fn a<F: Fn<usize>>(f: F) {}
+   |         ^^^^^^^^^ required by this bound in `a`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.