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

For a single impl candidate, try to unify it with error trait ref #115726

Merged
merged 2 commits into from
Oct 3, 2023
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
91 changes: 88 additions & 3 deletions compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// ignore-tidy-filelength :(

mod ambiguity;
pub mod on_unimplemented;
pub mod suggestions;
Expand Down Expand Up @@ -67,6 +69,7 @@ pub enum CandidateSimilarity {
pub struct ImplCandidate<'tcx> {
pub trait_ref: ty::TraitRef<'tcx>,
pub similarity: CandidateSimilarity,
impl_def_id: DefId,
}

enum GetSafeTransmuteErrorAndReason {
Expand Down Expand Up @@ -1331,6 +1334,7 @@ trait InferCtxtPrivExt<'tcx> {
body_def_id: LocalDefId,
err: &mut Diagnostic,
other: bool,
param_env: ty::ParamEnv<'tcx>,
) -> bool;

fn report_similar_impl_candidates_for_root_obligation(
Expand Down Expand Up @@ -1918,8 +1922,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {

let imp = self.tcx.impl_trait_ref(def_id).unwrap().skip_binder();

self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false)
.map(|similarity| ImplCandidate { trait_ref: imp, similarity })
self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false).map(
|similarity| ImplCandidate { trait_ref: imp, similarity, impl_def_id: def_id },
)
})
.collect();
if candidates.iter().any(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })) {
Expand All @@ -1938,7 +1943,82 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
body_def_id: LocalDefId,
err: &mut Diagnostic,
other: bool,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
// If we have a single implementation, try to unify it with the trait ref
// that failed. This should uncover a better hint for what *is* implemented.
if let [single] = &impl_candidates {
if self.probe(|_| {
let ocx = ObligationCtxt::new(self);
let obligation_trait_ref = self.instantiate_binder_with_placeholders(trait_ref);
let impl_args = self.fresh_args_for_item(DUMMY_SP, single.impl_def_id);
let impl_trait_ref = ocx.normalize(
&ObligationCause::dummy(),
param_env,
ty::EarlyBinder::bind(single.trait_ref).instantiate(self.tcx, impl_args),
);

ocx.register_obligations(
self.tcx
.predicates_of(single.impl_def_id)
.instantiate(self.tcx, impl_args)
.into_iter()
.map(|(clause, _)| {
Obligation::new(self.tcx, ObligationCause::dummy(), param_env, clause)
}),
);
if !ocx.select_where_possible().is_empty() {
return false;
}

let mut terrs = vec![];
for (obligation_arg, impl_arg) in
std::iter::zip(obligation_trait_ref.args, impl_trait_ref.args)
{
if let Err(terr) =
ocx.eq(&ObligationCause::dummy(), param_env, impl_arg, obligation_arg)
{
terrs.push(terr);
}
if !ocx.select_where_possible().is_empty() {
return false;
}
}

// Literally nothing unified, just give up.
if terrs.len() == impl_trait_ref.args.len() {
return false;
}

let cand =
self.resolve_vars_if_possible(impl_trait_ref).fold_with(&mut BottomUpFolder {
tcx: self.tcx,
ty_op: |ty| ty,
lt_op: |lt| lt,
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
});
err.highlighted_help(vec![
(format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle),
("is".to_string(), Style::Highlight),
(" implemented for `".to_string(), Style::NoStyle),
(cand.self_ty().to_string(), Style::Highlight),
("`".to_string(), Style::NoStyle),
]);

if let [TypeError::Sorts(exp_found)] = &terrs[..] {
let exp_found = self.resolve_vars_if_possible(*exp_found);
err.help(format!(
"for that trait implementation, expected `{}`, found `{}`",
exp_found.expected, exp_found.found
));
}

true
}) {
return true;
}
}

let other = if other { "other " } else { "" };
let report = |candidates: Vec<TraitRef<'tcx>>, err: &mut Diagnostic| {
if candidates.is_empty() {
Expand Down Expand Up @@ -2062,9 +2142,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
})
.collect();
impl_candidates.sort_by_key(|cand| (cand.similarity, cand.trait_ref));
let mut impl_candidates: Vec<_> =
impl_candidates.into_iter().map(|cand| cand.trait_ref).collect();
impl_candidates.dedup();

report(impl_candidates.into_iter().map(|cand| cand.trait_ref).collect(), err)
report(impl_candidates, err)
}

fn report_similar_impl_candidates_for_root_obligation(
Expand Down Expand Up @@ -2108,6 +2190,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
body_def_id,
err,
true,
obligation.param_env,
);
}
}
Expand Down Expand Up @@ -2316,6 +2399,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
obligation.cause.body_id,
&mut err,
false,
obligation.param_env,
);
}
}
Expand Down Expand Up @@ -3051,6 +3135,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
body_def_id,
err,
true,
obligation.param_env,
) {
self.report_similar_impl_candidates_for_root_obligation(
&obligation,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error[E0277]: the trait bound `A<_>: Bar<_>` is not satisfied
LL | let _ = A;
| ^ the trait `Bar<_>` is not implemented for `A<_>`
|
= help: the trait `Bar<N>` is implemented for `A<7>`
= help: the trait `Bar<_>` is implemented for `A<7>`
Copy link
Member Author

Choose a reason for hiding this comment

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

This isn't better but it's also not worse 💀

Copy link
Contributor

Choose a reason for hiding this comment

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

While this case isn't that much worse, there are cases where it shows something like UwU<_> is implemented for OwO<_> which no longer indicates that the type that's being printed as _ is the same in both cases. (I dislike that that sort of printing for types is ever done, but that's not specific to this PR.)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I wonder if we could plug up the remaining infer vars here, so that those two Owo<_> and Uwu<_> are re-connected with some placeholder name.

note: required by a bound in `A`
--> $DIR/unused-substs-1.rs:9:11
|
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/generic-const-items/unsatisfied-bounds.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ LL | let () = K::<()>;
| ^^ the trait `From<()>` is not implemented for `Infallible`
|
= help: the trait `From<!>` is implemented for `Infallible`
= help: for that trait implementation, expected `!`, found `()`
note: required by a bound in `K`
--> $DIR/unsatisfied-bounds.rs:12:17
|
Expand Down Expand Up @@ -48,6 +49,7 @@ LL | let _ = <() as Trait<&'static str>>::B::<()>;
| ^^ the trait `From<()>` is not implemented for `Infallible`
|
= help: the trait `From<!>` is implemented for `Infallible`
= help: for that trait implementation, expected `!`, found `()`
note: required by a bound in `Trait::B`
--> $DIR/unsatisfied-bounds.rs:21:21
|
Expand Down
5 changes: 3 additions & 2 deletions tests/ui/impl-trait/issues/issue-62742.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
LL | WrongImpl::foo(0i32);
| ^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>`
|
= help: the trait `Raw<[T]>` is implemented for `RawImpl<T>`
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
note: required by a bound in `SafeImpl`
--> $DIR/issue-62742.rs:26:35
|
Expand Down Expand Up @@ -42,7 +42,8 @@ error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied
LL | WrongImpl::<()>::foo(0i32);
| ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>`
|
= help: the trait `Raw<[T]>` is implemented for `RawImpl<T>`
= help: the trait `Raw<[()]>` is implemented for `RawImpl<()>`
= help: for that trait implementation, expected `[()]`, found `()`
note: required by a bound in `SafeImpl`
--> $DIR/issue-62742.rs:26:35
|
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/indexing/index-help.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ LL | x[0i32];
| ^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `SliceIndex<[{integer}]>` is not implemented for `i32`
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
= help: the trait `SliceIndex<[{integer}]>` is implemented for `usize`
= help: for that trait implementation, expected `usize`, found `i32`
= note: required for `Vec<{integer}>` to implement `Index<i32>`

error: aborting due to previous error
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/indexing/indexing-requires-a-uint.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ LL | [0][0u8];
| ^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `SliceIndex<[{integer}]>` is not implemented for `u8`
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
= help: the trait `SliceIndex<[{integer}]>` is implemented for `usize`
= help: for that trait implementation, expected `usize`, found `u8`
= note: required for `[{integer}]` to implement `Index<u8>`

error[E0308]: mismatched types
Expand Down
24 changes: 16 additions & 8 deletions tests/ui/integral-indexing.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ LL | v[3u8];
| ^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `SliceIndex<[isize]>` is not implemented for `u8`
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
= help: the trait `SliceIndex<[isize]>` is implemented for `usize`
= help: for that trait implementation, expected `usize`, found `u8`
= note: required for `Vec<isize>` to implement `Index<u8>`

error[E0277]: the type `[isize]` cannot be indexed by `i8`
Expand All @@ -15,7 +16,8 @@ LL | v[3i8];
| ^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `SliceIndex<[isize]>` is not implemented for `i8`
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
= help: the trait `SliceIndex<[isize]>` is implemented for `usize`
= help: for that trait implementation, expected `usize`, found `i8`
= note: required for `Vec<isize>` to implement `Index<i8>`

error[E0277]: the type `[isize]` cannot be indexed by `u32`
Expand All @@ -25,7 +27,8 @@ LL | v[3u32];
| ^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `SliceIndex<[isize]>` is not implemented for `u32`
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
= help: the trait `SliceIndex<[isize]>` is implemented for `usize`
= help: for that trait implementation, expected `usize`, found `u32`
= note: required for `Vec<isize>` to implement `Index<u32>`

error[E0277]: the type `[isize]` cannot be indexed by `i32`
Expand All @@ -35,7 +38,8 @@ LL | v[3i32];
| ^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `SliceIndex<[isize]>` is not implemented for `i32`
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
= help: the trait `SliceIndex<[isize]>` is implemented for `usize`
= help: for that trait implementation, expected `usize`, found `i32`
= note: required for `Vec<isize>` to implement `Index<i32>`

error[E0277]: the type `[u8]` cannot be indexed by `u8`
Expand All @@ -45,7 +49,8 @@ LL | s.as_bytes()[3u8];
| ^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `SliceIndex<[u8]>` is not implemented for `u8`
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
= help: the trait `SliceIndex<[u8]>` is implemented for `usize`
= help: for that trait implementation, expected `usize`, found `u8`
= note: required for `[u8]` to implement `Index<u8>`

error[E0277]: the type `[u8]` cannot be indexed by `i8`
Expand All @@ -55,7 +60,8 @@ LL | s.as_bytes()[3i8];
| ^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `SliceIndex<[u8]>` is not implemented for `i8`
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
= help: the trait `SliceIndex<[u8]>` is implemented for `usize`
= help: for that trait implementation, expected `usize`, found `i8`
= note: required for `[u8]` to implement `Index<i8>`

error[E0277]: the type `[u8]` cannot be indexed by `u32`
Expand All @@ -65,7 +71,8 @@ LL | s.as_bytes()[3u32];
| ^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `SliceIndex<[u8]>` is not implemented for `u32`
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
= help: the trait `SliceIndex<[u8]>` is implemented for `usize`
= help: for that trait implementation, expected `usize`, found `u32`
= note: required for `[u8]` to implement `Index<u32>`

error[E0277]: the type `[u8]` cannot be indexed by `i32`
Expand All @@ -75,7 +82,8 @@ LL | s.as_bytes()[3i32];
| ^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `SliceIndex<[u8]>` is not implemented for `i32`
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
= help: the trait `SliceIndex<[u8]>` is implemented for `usize`
= help: for that trait implementation, expected `usize`, found `i32`
= note: required for `[u8]` to implement `Index<i32>`

error: aborting due to 8 previous errors
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/issues/issue-34334.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_rece
| ^^^^^^^ value of type `Vec<(u32, _, _)>` cannot be built from `std::iter::Iterator<Item=()>`
|
= help: the trait `FromIterator<()>` is not implemented for `Vec<(u32, _, _)>`
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
= help: the trait `FromIterator<(u32, _, _)>` is implemented for `Vec<(u32, _, _)>`
= help: for that trait implementation, expected `(u32, _, _)`, found `()`
note: the method call chain might not have had the expected associated types
--> $DIR/issue-34334.rs:5:43
|
Expand Down
1 change: 1 addition & 0 deletions tests/ui/issues/issue-45801.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ LL | req.get_ref::<Params>();
| ^^^^^^^ the trait `Plugin<i32>` is not implemented for `Params`
|
= help: the trait `Plugin<Foo>` is implemented for `Params`
= help: for that trait implementation, expected `Foo`, found `i32`

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ LL | let x2: Vec<f64> = x1.into_iter().collect();
| ^^^^^^^ value of type `Vec<f64>` cannot be built from `std::iter::Iterator<Item=&f64>`
|
= help: the trait `FromIterator<&f64>` is not implemented for `Vec<f64>`
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
= help: the trait `FromIterator<f64>` is implemented for `Vec<f64>`
= help: for that trait implementation, expected `f64`, found `&f64`
note: the method call chain might not have had the expected associated types
--> $DIR/issue-66923-show-error-for-correct-call.rs:8:27
|
Expand All @@ -25,7 +26,8 @@ LL | let x3 = x1.into_iter().collect::<Vec<f64>>();
| required by a bound introduced by this call
|
= help: the trait `FromIterator<&f64>` is not implemented for `Vec<f64>`
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
= help: the trait `FromIterator<f64>` is implemented for `Vec<f64>`
= help: for that trait implementation, expected `f64`, found `&f64`
note: the method call chain might not have had the expected associated types
--> $DIR/issue-66923-show-error-for-correct-call.rs:12:17
|
Expand Down
6 changes: 4 additions & 2 deletions tests/ui/iterators/invalid-iterator-chain.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ LL | i.collect()
| ^^^^^^^ value of type `Vec<X>` cannot be built from `std::iter::Iterator<Item=&X>`
|
= help: the trait `FromIterator<&X>` is not implemented for `Vec<X>`
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
= help: the trait `FromIterator<X>` is implemented for `Vec<X>`
= help: for that trait implementation, expected `X`, found `&X`
note: the method call chain might not have had the expected associated types
--> $DIR/invalid-iterator-chain.rs:4:26
|
Expand Down Expand Up @@ -159,7 +160,8 @@ LL | let g: Vec<i32> = f.collect();
| ^^^^^^^ value of type `Vec<i32>` cannot be built from `std::iter::Iterator<Item=()>`
|
= help: the trait `FromIterator<()>` is not implemented for `Vec<i32>`
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
= help: the trait `FromIterator<i32>` is implemented for `Vec<i32>`
= help: for that trait implementation, expected `i32`, found `()`
note: the method call chain might not have had the expected associated types
--> $DIR/invalid-iterator-chain.rs:44:15
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ LL | <E as From<_>>::from(never);
| ^ the trait `From<()>` is not implemented for `E`
|
= help: the trait `From<!>` is implemented for `E`
= help: for that trait implementation, expected `!`, found `()`

error: aborting due to previous error

Expand Down
3 changes: 2 additions & 1 deletion tests/ui/on-unimplemented/impl-substs.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ LL | Foo::<usize>::foo((1i32, 1i32, 1i32));
| required by a bound introduced by this call
|
= help: the trait `Foo<usize>` is not implemented for `(i32, i32, i32)`
= help: the trait `Foo<A>` is implemented for `(A, B, C)`
= help: the trait `Foo<i32>` is implemented for `(i32, i32, i32)`
= help: for that trait implementation, expected `i32`, found `usize`

error: aborting due to previous error

Expand Down
3 changes: 3 additions & 0 deletions tests/ui/on-unimplemented/on-impl.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ LL | Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
|
= help: the trait `Index<u32>` is not implemented for `[i32]`
= help: the trait `Index<usize>` is implemented for `[i32]`
= help: for that trait implementation, expected `usize`, found `u32`

error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
--> $DIR/on-impl.rs:22:5
Expand All @@ -17,6 +18,7 @@ LL | Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
|
= help: the trait `Index<u32>` is not implemented for `[i32]`
= help: the trait `Index<usize>` is implemented for `[i32]`
= help: for that trait implementation, expected `usize`, found `u32`

error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
--> $DIR/on-impl.rs:22:5
Expand All @@ -26,6 +28,7 @@ LL | Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
|
= help: the trait `Index<u32>` is not implemented for `[i32]`
= help: the trait `Index<usize>` is implemented for `[i32]`
= help: for that trait implementation, expected `usize`, found `u32`

error: aborting due to 3 previous errors

Expand Down
Loading
Loading