Skip to content

Commit 750f04d

Browse files
Implement special-cased projection error message for some common traits
1 parent d394408 commit 750f04d

25 files changed

+80
-43
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+49-13
Original file line numberDiff line numberDiff line change
@@ -1315,6 +1315,13 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
13151315
error: &MismatchedProjectionTypes<'tcx>,
13161316
);
13171317

1318+
fn maybe_detailed_projection_msg(
1319+
&self,
1320+
pred: ty::ProjectionPredicate<'tcx>,
1321+
normalized_ty: ty::Term<'tcx>,
1322+
expected_ty: ty::Term<'tcx>,
1323+
) -> Option<String>;
1324+
13181325
fn fuzzy_match_tys(
13191326
&self,
13201327
a: Ty<'tcx>,
@@ -1542,23 +1549,19 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
15421549
normalized_ty,
15431550
data.term,
15441551
) {
1545-
values = Some(infer::ValuePairs::Terms(ExpectedFound::new(
1546-
is_normalized_ty_expected,
1547-
normalized_ty,
1548-
data.term,
1549-
)));
1552+
values = Some((data, is_normalized_ty_expected, normalized_ty, data.term));
15501553
err_buf = error;
15511554
err = &err_buf;
15521555
}
15531556
}
15541557

1555-
let mut diag = struct_span_err!(
1556-
self.tcx.sess,
1557-
obligation.cause.span,
1558-
E0271,
1559-
"type mismatch resolving `{}`",
1560-
predicate
1561-
);
1558+
let msg = values
1559+
.and_then(|(predicate, _, normalized_ty, expected_ty)| {
1560+
self.maybe_detailed_projection_msg(predicate, normalized_ty, expected_ty)
1561+
})
1562+
.unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate));
1563+
let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
1564+
15621565
let secondary_span = match predicate.kind().skip_binder() {
15631566
ty::PredicateKind::Projection(proj) => self
15641567
.tcx
@@ -1596,7 +1599,13 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
15961599
&mut diag,
15971600
&obligation.cause,
15981601
secondary_span,
1599-
values,
1602+
values.map(|(_, is_normalized_ty_expected, normalized_ty, term)| {
1603+
infer::ValuePairs::Terms(ExpectedFound::new(
1604+
is_normalized_ty_expected,
1605+
normalized_ty,
1606+
term,
1607+
))
1608+
}),
16001609
err,
16011610
true,
16021611
false,
@@ -1606,6 +1615,33 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
16061615
});
16071616
}
16081617

1618+
fn maybe_detailed_projection_msg(
1619+
&self,
1620+
pred: ty::ProjectionPredicate<'tcx>,
1621+
normalized_ty: ty::Term<'tcx>,
1622+
expected_ty: ty::Term<'tcx>,
1623+
) -> Option<String> {
1624+
let trait_def_id = pred.projection_ty.trait_def_id(self.tcx);
1625+
let self_ty = pred.projection_ty.self_ty();
1626+
1627+
if Some(pred.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() {
1628+
Some(format!(
1629+
"expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it actually returns `{normalized_ty}`",
1630+
fn_kind = self_ty.prefix_string(self.tcx)
1631+
))
1632+
} else if Some(trait_def_id) == self.tcx.lang_items().future_trait() {
1633+
Some(format!(
1634+
"expected `{self_ty}` to be a future that yields `{expected_ty}`, but it actually yields `{normalized_ty}`"
1635+
))
1636+
} else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
1637+
Some(format!(
1638+
"expected `{self_ty}` to be an iterator of `{expected_ty}`, but it actually returns items of `{normalized_ty}`"
1639+
))
1640+
} else {
1641+
None
1642+
}
1643+
}
1644+
16091645
fn fuzzy_match_tys(
16101646
&self,
16111647
mut a: Ty<'tcx>,

src/test/ui/associated-types/associated-types-overridden-binding-2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ trait I32Iterator = Iterator<Item = i32>;
44

55
fn main() {
66
let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
7-
//~^ ERROR type mismatch
7+
//~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator of `i32`, but it actually returns items of `u32`
88
}

src/test/ui/associated-types/associated-types-overridden-binding-2.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == i32`
1+
error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator of `i32`, but it actually returns items of `u32`
22
--> $DIR/associated-types-overridden-binding-2.rs:6:43
33
|
44
LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();

src/test/ui/async-await/async-block-control-flow-static-semantics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ fn return_targets_async_block_not_fn() -> u8 {
1515
return 0u8;
1616
};
1717
let _: &dyn Future<Output = ()> = &block;
18-
//~^ ERROR type mismatch
18+
//~^ ERROR expected `impl Future<Output = u8>` to be a future that yields `()`, but it actually yields `u8`
1919
}
2020

2121
async fn return_targets_async_block_not_async_fn() -> u8 {
@@ -24,7 +24,7 @@ async fn return_targets_async_block_not_async_fn() -> u8 {
2424
return 0u8;
2525
};
2626
let _: &dyn Future<Output = ()> = &block;
27-
//~^ ERROR type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
27+
//~^ ERROR expected `impl Future<Output = u8>` to be a future that yields `()`, but it actually yields `u8`
2828
}
2929

3030
fn no_break_in_async_block() {

src/test/ui/async-await/async-block-control-flow-static-semantics.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ LL | |
3131
LL | | }
3232
| |_^ expected `u8`, found `()`
3333

34-
error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
34+
error[E0271]: expected `impl Future<Output = u8>` to be a future that yields `()`, but it actually yields `u8`
3535
--> $DIR/async-block-control-flow-static-semantics.rs:26:39
3636
|
3737
LL | let _: &dyn Future<Output = ()> = &block;
@@ -47,7 +47,7 @@ LL | fn return_targets_async_block_not_fn() -> u8 {
4747
| |
4848
| implicitly returns `()` as its body has no tail or `return` expression
4949

50-
error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
50+
error[E0271]: expected `impl Future<Output = u8>` to be a future that yields `()`, but it actually yields `u8`
5151
--> $DIR/async-block-control-flow-static-semantics.rs:17:39
5252
|
5353
LL | let _: &dyn Future<Output = ()> = &block;

src/test/ui/hrtb/issue-62203-hrtb-ice.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ fn main() {
3838
let v = Unit2.m(
3939
//~^ ERROR type mismatch
4040
L {
41-
//~^ ERROR type mismatch
41+
//~^ ERROR to be a closure that returns `Unit3`, but it actually returns `Unit4`
4242
f : |x| { drop(x); Unit4 }
4343
});
4444
}

src/test/ui/hrtb/issue-62203-hrtb-ice.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ LL | where
2222
LL | F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>,
2323
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m`
2424

25-
error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20] as FnOnce<((&'r u8,),)>>::Output == Unit3`
25+
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`
2626
--> $DIR/issue-62203-hrtb-ice.rs:40:9
2727
|
2828
LL | let v = Unit2.m(

src/test/ui/impl-trait/issues/issue-78722.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ type F = impl core::future::Future<Output = u8>;
77
struct Bug {
88
V1: [(); {
99
fn concrete_use() -> F {
10-
//~^ ERROR type mismatch
10+
//~^ ERROR expected `impl Future<Output = ()>` to be a future that yields `u8`, but it actually yields `()`
1111
async {}
1212
}
1313
let f: F = async { 1 };

src/test/ui/impl-trait/issues/issue-78722.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ LL | let f: F = async { 1 };
1616
LL | }],
1717
| - value is dropped here
1818

19-
error[E0271]: type mismatch resolving `<impl Future<Output = ()> as Future>::Output == u8`
19+
error[E0271]: expected `impl Future<Output = ()>` to be a future that yields `u8`, but it actually yields `()`
2020
--> $DIR/issue-78722.rs:9:30
2121
|
2222
LL | fn concrete_use() -> F {

src/test/ui/intrinsics/const-eval-select-bad.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ fn baz(n: bool) -> i32 {
2727

2828
const fn return_ty_mismatch() {
2929
const_eval_select((1,), foo, bar);
30-
//~^ ERROR type mismatch
30+
//~^ ERROR expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it actually returns `bool`
3131
}
3232

3333
const fn args_ty_mismatch() {

src/test/ui/intrinsics/const-eval-select-bad.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ note: required by a bound in `const_eval_select`
5151
LL | G: FnOnce<ARG, Output = RET> + ~const Destruct,
5252
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
5353

54-
error[E0271]: type mismatch resolving `<fn(i32) -> bool {bar} as FnOnce<(i32,)>>::Output == i32`
54+
error[E0271]: expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it actually returns `bool`
5555
--> $DIR/const-eval-select-bad.rs:29:5
5656
|
5757
LL | const_eval_select((1,), foo, bar);

src/test/ui/issues/issue-31173.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub fn get_tok(it: &mut IntoIter<u8>) {
88
false
99
})
1010
.cloned()
11-
//~^ ERROR type mismatch resolving
11+
//~^ ERROR to be an iterator of `&_`, but it actually returns items of `u8`
1212
.collect(); //~ ERROR the method
1313
}
1414

src/test/ui/issues/issue-31173.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0271]: type mismatch resolving `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item == &_`
1+
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`
22
--> $DIR/issue-31173.rs:10:10
33
|
44
LL | .cloned()

src/test/ui/issues/issue-33941.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use std::collections::HashMap;
44

55
fn main() {
6-
for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch
7-
//~^ ERROR type mismatch
8-
//~| ERROR type mismatch
6+
for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)`
7+
//~^ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)`
8+
//~| ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)`
99
}

src/test/ui/issues/issue-33941.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_`
1+
error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)`
22
--> $DIR/issue-33941.rs:6:36
33
|
44
LL | for _ in HashMap::new().iter().cloned() {}
@@ -12,7 +12,7 @@ note: required by a bound in `cloned`
1212
LL | Self: Sized + Iterator<Item = &'a T>,
1313
| ^^^^^^^^^^^^ required by this bound in `cloned`
1414

15-
error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_`
15+
error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)`
1616
--> $DIR/issue-33941.rs:6:14
1717
|
1818
LL | for _ in HashMap::new().iter().cloned() {}
@@ -23,7 +23,7 @@ LL | for _ in HashMap::new().iter().cloned() {}
2323
= note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
2424
= note: required because of the requirements on the impl of `IntoIterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
2525

26-
error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_`
26+
error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)`
2727
--> $DIR/issue-33941.rs:6:14
2828
|
2929
LL | for _ in HashMap::new().iter().cloned() {}

src/test/ui/never_type/fallback-closure-wrap.fallback.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47] as FnOnce<()>>::Output == ()`
1+
error[E0271]: expected `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to be a closure that returns `()`, but it actually returns `!`
22
--> $DIR/fallback-closure-wrap.rs:18:31
33
|
44
LL | let error = Closure::wrap(Box::new(move || {

src/test/ui/never_type/fallback-closure-wrap.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use std::marker::PhantomData;
1616

1717
fn main() {
1818
let error = Closure::wrap(Box::new(move || {
19-
//[fallback]~^ ERROR type mismatch resolving
19+
//[fallback]~^ to be a closure that returns `()`, but it actually returns `!`
2020
panic!("Can't connect to server.");
2121
}) as Box<dyn FnMut()>);
2222
}

src/test/ui/traits/assoc-type-in-superbad.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ pub trait Foo: Iterator<Item=<Self as Foo>::Key> {
99
}
1010

1111
impl Foo for IntoIter<i32> {
12-
type Key = u32; //~ ERROR type mismatch
12+
type Key = u32;
13+
//~^ ERROR expected `std::vec::IntoIter<i32>` to be an iterator of `u32`, but it actually returns items of `i32`
1314
}
1415

1516
fn main() {

src/test/ui/traits/assoc-type-in-superbad.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0271]: type mismatch resolving `<std::vec::IntoIter<i32> as Iterator>::Item == u32`
1+
error[E0271]: expected `std::vec::IntoIter<i32>` to be an iterator of `u32`, but it actually returns items of `i32`
22
--> $DIR/assoc-type-in-superbad.rs:12:16
33
|
44
LL | type Key = u32;

src/test/ui/type-alias-impl-trait/issue-57961.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ trait Foo {
88

99
impl Foo for () {
1010
type Bar = std::vec::IntoIter<u32>;
11-
//~^ ERROR type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X
11+
//~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator of `X`, but it actually returns items of `u32`
1212
}
1313

1414
fn incoherent() {

src/test/ui/type-alias-impl-trait/issue-57961.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X`
1+
error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator of `X`, but it actually returns items of `u32`
22
--> $DIR/issue-57961.rs:10:16
33
|
44
LL | type X = impl Sized;

src/test/ui/type-alias-impl-trait/issue-98604.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ async fn test() {}
99
#[allow(unused_must_use)]
1010
fn main() {
1111
Box::new(test) as AsyncFnPtr;
12-
//~^ ERROR type mismatch
12+
//~^ 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 = ()>`
1313
}

src/test/ui/type-alias-impl-trait/issue-98604.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0271]: type mismatch resolving `<fn() -> impl Future<Output = ()> {test} as FnOnce<()>>::Output == Pin<Box<(dyn Future<Output = ()> + 'static)>>`
1+
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 = ()>`
22
--> $DIR/issue-98604.rs:11:5
33
|
44
LL | Box::new(test) as AsyncFnPtr;

src/test/ui/type-alias-impl-trait/issue-98608.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ fn hi() -> impl Sized { std::ptr::null::<u8>() }
22

33
fn main() {
44
let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi);
5-
//~^ ERROR type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>`
5+
//~^ ERROR expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box<u8>`, but it actually returns `impl Sized`
66
let boxed = b();
77
let null = *boxed;
88
println!("{null:?}");

src/test/ui/type-alias-impl-trait/issue-98608.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0271]: type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>`
1+
error[E0271]: expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box<u8>`, but it actually returns `impl Sized`
22
--> $DIR/issue-98608.rs:4:39
33
|
44
LL | fn hi() -> impl Sized { std::ptr::null::<u8>() }

0 commit comments

Comments
 (0)