Skip to content

Commit

Permalink
Auto merge of #98863 - compiler-errors:projection-msg, r=estebank
Browse files Browse the repository at this point in the history
Implement special-cased projection error message for some common traits

Not sure what the best phrasing is, but I feel like these are more clear than the plain `<Type as Iterator>::Output == Type` messages.

If this is actually a good idea, are there any other traits this could benefit?
  • Loading branch information
bors committed Aug 8, 2022
2 parents 9b8cfc1 + 3fdf3cb commit f03ce30
Show file tree
Hide file tree
Showing 25 changed files with 124 additions and 78 deletions.
62 changes: 49 additions & 13 deletions compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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 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 resolves to `{expected_ty}`, but it resolves to `{normalized_ty}`"
))
} else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
Some(format!(
"expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it yields `{normalized_ty}`"
))
} else {
None
}
}

fn fuzzy_match_tys(
&self,
mut a: Ty<'tcx>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 that yields `i32`, but it yields `u32`
}
Original file line number Diff line number Diff line change
@@ -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 that yields `i32`, but it yields `u32`
--> $DIR/associated-types-overridden-binding-2.rs:6:43
|
LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn return_targets_async_block_not_fn() -> u8 {
return 0u8;
};
let _: &dyn Future<Output = ()> = &block;
//~^ ERROR type mismatch
//~^ ERROR expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
}

async fn return_targets_async_block_not_async_fn() -> u8 {
Expand All @@ -24,7 +24,7 @@ async fn return_targets_async_block_not_async_fn() -> u8 {
return 0u8;
};
let _: &dyn Future<Output = ()> = &block;
//~^ ERROR type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
//~^ ERROR expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
}

fn no_break_in_async_block() {
Expand All @@ -42,7 +42,9 @@ fn no_break_in_async_block_even_with_outer_loop() {
}

struct MyErr;
fn err() -> Result<u8, MyErr> { Err(MyErr) }
fn err() -> Result<u8, MyErr> {
Err(MyErr)
}

fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> {
//~^ ERROR mismatched types
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 resolves to `()`, but it resolves to `u8`
--> $DIR/async-block-control-flow-static-semantics.rs:26:39
|
LL | let _: &dyn Future<Output = ()> = &block;
Expand All @@ -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 resolves to `()`, but it resolves to `u8`
--> $DIR/async-block-control-flow-static-semantics.rs:17:39
|
LL | let _: &dyn Future<Output = ()> = &block;
Expand All @@ -56,7 +56,7 @@ LL | let _: &dyn Future<Output = ()> = &block;
= note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>`

error[E0308]: mismatched types
--> $DIR/async-block-control-flow-static-semantics.rs:47:44
--> $DIR/async-block-control-flow-static-semantics.rs:49:44
|
LL | fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> {
| ---------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()`
Expand All @@ -67,7 +67,7 @@ LL | fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> {
found unit type `()`

error[E0308]: mismatched types
--> $DIR/async-block-control-flow-static-semantics.rs:56:50
--> $DIR/async-block-control-flow-static-semantics.rs:58:50
|
LL | fn rethrow_targets_async_block_not_async_fn() -> Result<u8, MyErr> {
| ---------------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()`
Expand Down
10 changes: 7 additions & 3 deletions src/test/ui/hrtb/issue-62203-hrtb-ice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,13 @@ fn main() {
let v = Unit2.m(
//~^ ERROR type mismatch
L {
//~^ ERROR type mismatch
f : |x| { drop(x); Unit4 }
});
//~^ ERROR to be a closure that returns `Unit3`, but it returns `Unit4`
f: |x| {
drop(x);
Unit4
},
},
);
}

impl<'a> Ty<'a> for Unit2 {
Expand Down
15 changes: 9 additions & 6 deletions src/test/ui/hrtb/issue-62203-hrtb-ice.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
--> $DIR/issue-62203-hrtb-ice.rs:38:19
|
LL | let v = Unit2.m(
| ^ type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
| ^ type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
|
note: expected this to be `<_ as Ty<'_>>::V`
--> $DIR/issue-62203-hrtb-ice.rs:21:14
Expand All @@ -22,19 +22,22 @@ 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:16: 42:19]` to be a closure that returns `Unit3`, but it returns `Unit4`
--> $DIR/issue-62203-hrtb-ice.rs:40:9
|
LL | let v = Unit2.m(
| - required by a bound introduced by this call
LL |
LL | / L {
LL | |
LL | | f : |x| { drop(x); Unit4 }
LL | | });
LL | | f: |x| {
LL | | drop(x);
LL | | Unit4
LL | | },
LL | | },
| |_________^ expected struct `Unit3`, found struct `Unit4`
|
note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]>`
note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]>`
--> $DIR/issue-62203-hrtb-ice.rs:17:16
|
LL | impl<'a, A, T> T0<'a, A> for L<T>
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/impl-trait/issues/issue-78722.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 resolves to `u8`, but it resolves to `()`
async {}
}
let f: F = async { 1 };
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/impl-trait/issues/issue-78722.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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 resolves to `u8`, but it resolves to `()`
--> $DIR/issue-78722.rs:9:30
|
LL | fn concrete_use() -> F {
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/intrinsics/const-eval-select-bad.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 returns `bool`
}

const fn args_ty_mismatch() {
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/intrinsics/const-eval-select-bad.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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 returns `bool`
--> $DIR/const-eval-select-bad.rs:29:5
|
LL | const_eval_select((1,), foo, bar);
Expand Down
11 changes: 6 additions & 5 deletions src/test/ui/issues/issue-31173.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ use std::vec::IntoIter;
pub fn get_tok(it: &mut IntoIter<u8>) {
let mut found_e = false;

let temp: Vec<u8> = it.take_while(|&x| {
found_e = true;
false
})
let temp: Vec<u8> = it
.take_while(|&x| {
found_e = true;
false
})
.cloned()
//~^ ERROR type mismatch resolving
//~^ ERROR to be an iterator that yields `&_`, but it yields `u8`
.collect(); //~ ERROR the method
}

Expand Down
18 changes: 9 additions & 9 deletions src/test/ui/issues/issue-31173.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0271]: type mismatch resolving `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item == &_`
--> $DIR/issue-31173.rs:10:10
error[E0271]: expected `TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>` to be an iterator that yields `&_`, but it yields `u8`
--> $DIR/issue-31173.rs:11:10
|
LL | .cloned()
| ^^^^^^ expected reference, found `u8`
Expand All @@ -12,11 +12,11 @@ note: required by a bound in `cloned`
LL | Self: Sized + Iterator<Item = &'a T>,
| ^^^^^^^^^^^^ required by this bound in `cloned`

error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>`, but its trait bounds were not satisfied
--> $DIR/issue-31173.rs:12:10
error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>`, but its trait bounds were not satisfied
--> $DIR/issue-31173.rs:13:10
|
LL | .collect();
| ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>` due to unsatisfied trait bounds
| ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>` due to unsatisfied trait bounds
|
::: $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
|
Expand All @@ -29,10 +29,10 @@ LL | pub struct TakeWhile<I, P> {
| -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_`
|
= note: the following trait bounds were not satisfied:
`<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item = &_`
which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
`Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
`<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]> as Iterator>::Item = &_`
which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
`Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`

error: aborting due to 2 previous errors

Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/issues/issue-33941.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 that yields `&_`, but it yields `(&_, &_)`
//~^ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
//~| ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
}
6 changes: 3 additions & 3 deletions src/test/ui/issues/issue-33941.stderr
Original file line number Diff line number Diff line change
@@ -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 that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:36
|
LL | for _ in HashMap::new().iter().cloned() {}
Expand All @@ -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 that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:14
|
LL | for _ in HashMap::new().iter().cloned() {}
Expand All @@ -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 that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:14
|
LL | for _ in HashMap::new().iter().cloned() {}
Expand Down
Original file line number Diff line number Diff line change
@@ -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 returns `!`
--> $DIR/fallback-closure-wrap.rs:18:31
|
LL | let error = Closure::wrap(Box::new(move || {
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/never_type/fallback-closure-wrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 returns `!`
panic!("Can't connect to server.");
}) as Box<dyn FnMut()>);
}
Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/traits/assoc-type-in-superbad.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

use std::vec::IntoIter;

pub trait Foo: Iterator<Item=<Self as Foo>::Key> {
pub trait Foo: Iterator<Item = <Self as Foo>::Key> {
type 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 that yields `u32`, but it yields `i32`
}

fn main() {
}
fn main() {}
Loading

0 comments on commit f03ce30

Please sign in to comment.