diff options
| author | Dylan DPC <99973273+Dylan-DPC@users.noreply.github.com> | 2022-08-16 18:16:11 +0530 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-08-16 18:16:11 +0530 |
| commit | 070de4bc4866fe8f36bf1538e01e10eab25f3c79 (patch) | |
| tree | e18648a3d3821cb169d2cc855a56e0b84b0e71cc /compiler | |
| parent | 14a459bf37bc19476d43e0045d078121c12d3fef (diff) | |
| parent | 1c084f15f308f1d977fd763c3d8bed831b44abf2 (diff) | |
| download | rust-070de4bc4866fe8f36bf1538e01e10eab25f3c79.tar.gz rust-070de4bc4866fe8f36bf1538e01e10eab25f3c79.zip | |
Rollup merge of #99942 - compiler-errors:nonsense-un-tupled-fn-trait-error, r=cjgillot
Fix nonsense non-tupled `Fn` trait error
Given this code:
```rust
#![feature(unboxed_closures)]
fn a<F: Fn<usize>>(f: F) {}
fn main() {
a(|_: usize| {});
}
```
We currently emit this error:
```
error[E0631]: type mismatch in closure arguments
--> src/main.rs:6:5
|
6 | a(|_: usize| {});
| ^ ---------- found signature of `fn(usize) -> _`
| |
| expected signature of `fn(usize) -> _`
|
note: required by a bound in `a`
--> src/main.rs:3:9
|
3 | fn a<F: Fn<usize>>(f: F) {}
| ^^^^^^^^^ required by this bound in `a`
For more information about this error, try `rustc --explain E0631`.
error: could not compile `playground` due to previous error
```
Notably, it says the same thing for "expected" and "found"!
Fix the output so that we instead emit:
```
error[E0308]: mismatched types
--> /home/gh-compiler-errors/test.rs:6:5
|
6 | a(|_: usize| {});
| ^ types differ
|
= note: expected trait `Fn<usize>`
found trait `Fn<(usize,)>`
note: required by a bound in `a`
--> /home/gh-compiler-errors/test.rs:3:9
|
3 | fn a<F: Fn<usize>>(f: F) {}
| ^^^^^^^^^ required by this bound in `a`
error: aborting due to previous error
```
The error could still use some work, namely the "mismatched types" part, but I'm leaving it a bit rough since the only way you'd ever get this error is when you're messing with `#![feature(unboxed_closures)]`.
Simply making sure we actually print out the difference in trait-refs is good enough for me. I could probably factor in some additional improvements if those are desired.
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/mod.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/mod.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/error.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs | 30 |
4 files changed, 52 insertions, 3 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, |
