diff options
25 files changed, 80 insertions, 43 deletions
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 e442c5c9189..911fb094b0c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1315,6 +1315,13 @@ trait InferCtxtPrivExt<'hir, 'tcx> { error: &MismatchedProjectionTypes<'tcx>, ); + fn maybe_detailed_projection_msg( + &self, + pred: ty::ProjectionPredicate<'tcx>, + normalized_ty: ty::Term<'tcx>, + expected_ty: ty::Term<'tcx>, + ) -> Option<String>; + fn fuzzy_match_tys( &self, a: Ty<'tcx>, @@ -1542,23 +1549,19 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { normalized_ty, data.term, ) { - values = Some(infer::ValuePairs::Terms(ExpectedFound::new( - is_normalized_ty_expected, - normalized_ty, - data.term, - ))); + values = Some((data, is_normalized_ty_expected, normalized_ty, data.term)); err_buf = error; err = &err_buf; } } - let mut diag = struct_span_err!( - self.tcx.sess, - obligation.cause.span, - E0271, - "type mismatch resolving `{}`", - predicate - ); + let msg = values + .and_then(|(predicate, _, normalized_ty, expected_ty)| { + self.maybe_detailed_projection_msg(predicate, normalized_ty, expected_ty) + }) + .unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate)); + let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}"); + let secondary_span = match predicate.kind().skip_binder() { ty::PredicateKind::Projection(proj) => self .tcx @@ -1596,7 +1599,13 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { &mut diag, &obligation.cause, secondary_span, - values, + values.map(|(_, is_normalized_ty_expected, normalized_ty, term)| { + infer::ValuePairs::Terms(ExpectedFound::new( + is_normalized_ty_expected, + normalized_ty, + term, + )) + }), err, true, false, @@ -1606,6 +1615,33 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { }); } + fn maybe_detailed_projection_msg( + &self, + pred: ty::ProjectionPredicate<'tcx>, + normalized_ty: ty::Term<'tcx>, + expected_ty: ty::Term<'tcx>, + ) -> Option<String> { + let trait_def_id = pred.projection_ty.trait_def_id(self.tcx); + let self_ty = pred.projection_ty.self_ty(); + + if Some(pred.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() { + Some(format!( + "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it actually returns `{normalized_ty}`", + fn_kind = self_ty.prefix_string(self.tcx) + )) + } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() { + Some(format!( + "expected `{self_ty}` to be a future that yields `{expected_ty}`, but it actually yields `{normalized_ty}`" + )) + } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) { + Some(format!( + "expected `{self_ty}` to be an iterator of `{expected_ty}`, but it actually returns items of `{normalized_ty}`" + )) + } else { + None + } + } + fn fuzzy_match_tys( &self, mut a: Ty<'tcx>, diff --git a/src/test/ui/associated-types/associated-types-overridden-binding-2.rs b/src/test/ui/associated-types/associated-types-overridden-binding-2.rs index 109feb8e969..525c4c81ed9 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding-2.rs +++ b/src/test/ui/associated-types/associated-types-overridden-binding-2.rs @@ -4,5 +4,5 @@ trait I32Iterator = Iterator<Item = i32>; fn main() { let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter(); - //~^ ERROR type mismatch + //~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator of `i32`, but it actually returns items of `u32` } diff --git a/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr b/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr index dbd9a44ed97..f7a1603844b 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr +++ b/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == i32` +error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator of `i32`, but it actually returns items of `u32` --> $DIR/associated-types-overridden-binding-2.rs:6:43 | LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter(); diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs index b831d610232..3f8cb7a5291 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs @@ -15,7 +15,7 @@ fn return_targets_async_block_not_fn() -> u8 { return 0u8; }; let _: &dyn Future<Output = ()> = █ - //~^ ERROR type mismatch + //~^ ERROR expected `impl Future<Output = u8>` to be a future that yields `()`, but it actually yields `u8` } async fn return_targets_async_block_not_async_fn() -> u8 { @@ -24,7 +24,7 @@ async fn return_targets_async_block_not_async_fn() -> u8 { return 0u8; }; let _: &dyn Future<Output = ()> = █ - //~^ ERROR type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()` + //~^ ERROR expected `impl Future<Output = u8>` to be a future that yields `()`, but it actually yields `u8` } fn no_break_in_async_block() { diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr index e5887689690..3d9adc04e17 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -31,7 +31,7 @@ LL | | LL | | } | |_^ expected `u8`, found `()` -error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()` +error[E0271]: expected `impl Future<Output = u8>` to be a future that yields `()`, but it actually yields `u8` --> $DIR/async-block-control-flow-static-semantics.rs:26:39 | LL | let _: &dyn Future<Output = ()> = █ @@ -47,7 +47,7 @@ LL | fn return_targets_async_block_not_fn() -> u8 { | | | implicitly returns `()` as its body has no tail or `return` expression -error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()` +error[E0271]: expected `impl Future<Output = u8>` to be a future that yields `()`, but it actually yields `u8` --> $DIR/async-block-control-flow-static-semantics.rs:17:39 | LL | let _: &dyn Future<Output = ()> = █ diff --git a/src/test/ui/hrtb/issue-62203-hrtb-ice.rs b/src/test/ui/hrtb/issue-62203-hrtb-ice.rs index 80f099ce3c8..19d7ff804e4 100644 --- a/src/test/ui/hrtb/issue-62203-hrtb-ice.rs +++ b/src/test/ui/hrtb/issue-62203-hrtb-ice.rs @@ -38,7 +38,7 @@ fn main() { let v = Unit2.m( //~^ ERROR type mismatch L { - //~^ ERROR type mismatch + //~^ ERROR to be a closure that returns `Unit3`, but it actually returns `Unit4` f : |x| { drop(x); Unit4 } }); } diff --git a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr index 79ef56b9fa5..e3055c1265e 100644 --- a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr +++ b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr @@ -22,7 +22,7 @@ LL | where LL | F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>, | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m` -error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20] as FnOnce<((&'r u8,),)>>::Output == Unit3` +error[E0271]: expected `[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]` to be a closure that returns `Unit3`, but it actually returns `Unit4` --> $DIR/issue-62203-hrtb-ice.rs:40:9 | LL | let v = Unit2.m( diff --git a/src/test/ui/impl-trait/issues/issue-78722.rs b/src/test/ui/impl-trait/issues/issue-78722.rs index 002e4cde40a..2d2b8192adc 100644 --- a/src/test/ui/impl-trait/issues/issue-78722.rs +++ b/src/test/ui/impl-trait/issues/issue-78722.rs @@ -7,7 +7,7 @@ type F = impl core::future::Future<Output = u8>; struct Bug { V1: [(); { fn concrete_use() -> F { - //~^ ERROR type mismatch + //~^ ERROR expected `impl Future<Output = ()>` to be a future that yields `u8`, but it actually yields `()` async {} } let f: F = async { 1 }; diff --git a/src/test/ui/impl-trait/issues/issue-78722.stderr b/src/test/ui/impl-trait/issues/issue-78722.stderr index 690d6abc766..f98655e9dff 100644 --- a/src/test/ui/impl-trait/issues/issue-78722.stderr +++ b/src/test/ui/impl-trait/issues/issue-78722.stderr @@ -16,7 +16,7 @@ LL | let f: F = async { 1 }; LL | }], | - value is dropped here -error[E0271]: type mismatch resolving `<impl Future<Output = ()> as Future>::Output == u8` +error[E0271]: expected `impl Future<Output = ()>` to be a future that yields `u8`, but it actually yields `()` --> $DIR/issue-78722.rs:9:30 | LL | fn concrete_use() -> F { diff --git a/src/test/ui/intrinsics/const-eval-select-bad.rs b/src/test/ui/intrinsics/const-eval-select-bad.rs index 52f4e594f1a..23b3f4fd825 100644 --- a/src/test/ui/intrinsics/const-eval-select-bad.rs +++ b/src/test/ui/intrinsics/const-eval-select-bad.rs @@ -27,7 +27,7 @@ fn baz(n: bool) -> i32 { const fn return_ty_mismatch() { const_eval_select((1,), foo, bar); - //~^ ERROR type mismatch + //~^ ERROR expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it actually returns `bool` } const fn args_ty_mismatch() { diff --git a/src/test/ui/intrinsics/const-eval-select-bad.stderr b/src/test/ui/intrinsics/const-eval-select-bad.stderr index 89dba12c818..efdb5c86508 100644 --- a/src/test/ui/intrinsics/const-eval-select-bad.stderr +++ b/src/test/ui/intrinsics/const-eval-select-bad.stderr @@ -51,7 +51,7 @@ note: required by a bound in `const_eval_select` LL | G: FnOnce<ARG, Output = RET> + ~const Destruct, | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` -error[E0271]: type mismatch resolving `<fn(i32) -> bool {bar} as FnOnce<(i32,)>>::Output == i32` +error[E0271]: expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it actually returns `bool` --> $DIR/const-eval-select-bad.rs:29:5 | LL | const_eval_select((1,), foo, bar); diff --git a/src/test/ui/issues/issue-31173.rs b/src/test/ui/issues/issue-31173.rs index 48061ae54ae..04e19c41756 100644 --- a/src/test/ui/issues/issue-31173.rs +++ b/src/test/ui/issues/issue-31173.rs @@ -8,7 +8,7 @@ pub fn get_tok(it: &mut IntoIter<u8>) { false }) .cloned() - //~^ ERROR type mismatch resolving + //~^ ERROR to be an iterator of `&_`, but it actually returns items of `u8` .collect(); //~ ERROR the method } diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr index 68337a715e1..43011d0d355 100644 --- a/src/test/ui/issues/issue-31173.stderr +++ b/src/test/ui/issues/issue-31173.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item == &_` +error[E0271]: expected `TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>` to be an iterator of `&_`, but it actually returns items of `u8` --> $DIR/issue-31173.rs:10:10 | LL | .cloned() diff --git a/src/test/ui/issues/issue-33941.rs b/src/test/ui/issues/issue-33941.rs index a1213623e6f..906f77559b4 100644 --- a/src/test/ui/issues/issue-33941.rs +++ b/src/test/ui/issues/issue-33941.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; fn main() { - for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch - //~^ ERROR type mismatch - //~| ERROR type mismatch + for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` + //~^ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` + //~| ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` } diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr index e1ce6eed98e..750f14c8239 100644 --- a/src/test/ui/issues/issue-33941.stderr +++ b/src/test/ui/issues/issue-33941.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_` +error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` --> $DIR/issue-33941.rs:6:36 | LL | for _ in HashMap::new().iter().cloned() {} @@ -12,7 +12,7 @@ note: required by a bound in `cloned` LL | Self: Sized + Iterator<Item = &'a T>, | ^^^^^^^^^^^^ required by this bound in `cloned` -error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_` +error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` --> $DIR/issue-33941.rs:6:14 | LL | for _ in HashMap::new().iter().cloned() {} @@ -23,7 +23,7 @@ LL | for _ in HashMap::new().iter().cloned() {} = note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` = note: required because of the requirements on the impl of `IntoIterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` -error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_` +error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` --> $DIR/issue-33941.rs:6:14 | LL | for _ in HashMap::new().iter().cloned() {} diff --git a/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr b/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr index 2acf44432c6..e1b6fee2ccc 100644 --- a/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr +++ b/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47] as FnOnce<()>>::Output == ()` +error[E0271]: expected `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to be a closure that returns `()`, but it actually returns `!` --> $DIR/fallback-closure-wrap.rs:18:31 | LL | let error = Closure::wrap(Box::new(move || { diff --git a/src/test/ui/never_type/fallback-closure-wrap.rs b/src/test/ui/never_type/fallback-closure-wrap.rs index af0577ac060..e9c343efb66 100644 --- a/src/test/ui/never_type/fallback-closure-wrap.rs +++ b/src/test/ui/never_type/fallback-closure-wrap.rs @@ -16,7 +16,7 @@ use std::marker::PhantomData; fn main() { let error = Closure::wrap(Box::new(move || { - //[fallback]~^ ERROR type mismatch resolving + //[fallback]~^ to be a closure that returns `()`, but it actually returns `!` panic!("Can't connect to server."); }) as Box<dyn FnMut()>); } diff --git a/src/test/ui/traits/assoc-type-in-superbad.rs b/src/test/ui/traits/assoc-type-in-superbad.rs index 579ce7cf706..925f84db37a 100644 --- a/src/test/ui/traits/assoc-type-in-superbad.rs +++ b/src/test/ui/traits/assoc-type-in-superbad.rs @@ -9,7 +9,8 @@ pub trait Foo: Iterator<Item=<Self as Foo>::Key> { } impl Foo for IntoIter<i32> { - type Key = u32; //~ ERROR type mismatch + type Key = u32; + //~^ ERROR expected `std::vec::IntoIter<i32>` to be an iterator of `u32`, but it actually returns items of `i32` } fn main() { diff --git a/src/test/ui/traits/assoc-type-in-superbad.stderr b/src/test/ui/traits/assoc-type-in-superbad.stderr index f3694791417..db691210b9c 100644 --- a/src/test/ui/traits/assoc-type-in-superbad.stderr +++ b/src/test/ui/traits/assoc-type-in-superbad.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<std::vec::IntoIter<i32> as Iterator>::Item == u32` +error[E0271]: expected `std::vec::IntoIter<i32>` to be an iterator of `u32`, but it actually returns items of `i32` --> $DIR/assoc-type-in-superbad.rs:12:16 | LL | type Key = u32; diff --git a/src/test/ui/type-alias-impl-trait/issue-57961.rs b/src/test/ui/type-alias-impl-trait/issue-57961.rs index 472886c9caa..639f3b72165 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57961.rs +++ b/src/test/ui/type-alias-impl-trait/issue-57961.rs @@ -8,7 +8,7 @@ trait Foo { impl Foo for () { type Bar = std::vec::IntoIter<u32>; - //~^ ERROR type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X + //~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator of `X`, but it actually returns items of `u32` } fn incoherent() { diff --git a/src/test/ui/type-alias-impl-trait/issue-57961.stderr b/src/test/ui/type-alias-impl-trait/issue-57961.stderr index ed4caf6ce68..907f10cc9a5 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57961.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57961.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X` +error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator of `X`, but it actually returns items of `u32` --> $DIR/issue-57961.rs:10:16 | LL | type X = impl Sized; diff --git a/src/test/ui/type-alias-impl-trait/issue-98604.rs b/src/test/ui/type-alias-impl-trait/issue-98604.rs index a4fd8a82a04..a2f29afd94c 100644 --- a/src/test/ui/type-alias-impl-trait/issue-98604.rs +++ b/src/test/ui/type-alias-impl-trait/issue-98604.rs @@ -9,5 +9,5 @@ async fn test() {} #[allow(unused_must_use)] fn main() { Box::new(test) as AsyncFnPtr; - //~^ ERROR type mismatch + //~^ ERROR expected `fn() -> impl Future<Output = ()> {test}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it actually returns `impl Future<Output = ()>` } diff --git a/src/test/ui/type-alias-impl-trait/issue-98604.stderr b/src/test/ui/type-alias-impl-trait/issue-98604.stderr index f04d1b4d787..5c8aae0da2e 100644 --- a/src/test/ui/type-alias-impl-trait/issue-98604.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-98604.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<fn() -> impl Future<Output = ()> {test} as FnOnce<()>>::Output == Pin<Box<(dyn Future<Output = ()> + 'static)>>` +error[E0271]: expected `fn() -> impl Future<Output = ()> {test}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it actually returns `impl Future<Output = ()>` --> $DIR/issue-98604.rs:11:5 | LL | Box::new(test) as AsyncFnPtr; diff --git a/src/test/ui/type-alias-impl-trait/issue-98608.rs b/src/test/ui/type-alias-impl-trait/issue-98608.rs index d75762a8b62..2f4cf7a0521 100644 --- a/src/test/ui/type-alias-impl-trait/issue-98608.rs +++ b/src/test/ui/type-alias-impl-trait/issue-98608.rs @@ -2,7 +2,7 @@ fn hi() -> impl Sized { std::ptr::null::<u8>() } fn main() { let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi); - //~^ ERROR type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>` + //~^ ERROR expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box<u8>`, but it actually returns `impl Sized` let boxed = b(); let null = *boxed; println!("{null:?}"); diff --git a/src/test/ui/type-alias-impl-trait/issue-98608.stderr b/src/test/ui/type-alias-impl-trait/issue-98608.stderr index 8f3ec7d9d16..c5eed7561c0 100644 --- a/src/test/ui/type-alias-impl-trait/issue-98608.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-98608.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>` +error[E0271]: expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box<u8>`, but it actually returns `impl Sized` --> $DIR/issue-98608.rs:4:39 | LL | fn hi() -> impl Sized { std::ptr::null::<u8>() } |
