Implement special-cased projection error message for some common traits
This commit is contained in:
parent
d394408fb3
commit
750f04d309
25 changed files with 80 additions and 43 deletions
|
@ -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>,
|
||||
|
|
|
@ -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`
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 = ()> = █
|
||||
|
|
|
@ -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 }
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 `(&_, &_)`
|
||||
}
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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 || {
|
||||
|
|
|
@ -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()>);
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = ()>`
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:?}");
|
||||
|
|
|
@ -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>() }
|
||||
|
|
Loading…
Add table
Reference in a new issue