Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement special-cased projection error message for some common traits #98863

Merged
merged 2 commits into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not for this PR: I would love to instead say "expected the closure to return Unit3..." and have a span label pointing at the closure, but we need to improve that in general.

--> $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