Skip to content

Commit ff3b15e

Browse files
authored
Rollup merge of #115726 - compiler-errors:better-error-ref, r=estebank
For a single impl candidate, try to unify it with error trait ref This allows us to point out an exact type mismatch when there's only one applicable impl. cc `@asquared31415` r? `@estebank`
2 parents 9eb87c3 + 0785167 commit ff3b15e

22 files changed

+157
-34
lines changed

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

+88-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// ignore-tidy-filelength :(
2+
13
mod ambiguity;
24
pub mod on_unimplemented;
35
pub mod suggestions;
@@ -67,6 +69,7 @@ pub enum CandidateSimilarity {
6769
pub struct ImplCandidate<'tcx> {
6870
pub trait_ref: ty::TraitRef<'tcx>,
6971
pub similarity: CandidateSimilarity,
72+
impl_def_id: DefId,
7073
}
7174

7275
enum GetSafeTransmuteErrorAndReason {
@@ -1331,6 +1334,7 @@ trait InferCtxtPrivExt<'tcx> {
13311334
body_def_id: LocalDefId,
13321335
err: &mut Diagnostic,
13331336
other: bool,
1337+
param_env: ty::ParamEnv<'tcx>,
13341338
) -> bool;
13351339

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

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

1921-
self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false)
1922-
.map(|similarity| ImplCandidate { trait_ref: imp, similarity })
1925+
self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false).map(
1926+
|similarity| ImplCandidate { trait_ref: imp, similarity, impl_def_id: def_id },
1927+
)
19231928
})
19241929
.collect();
19251930
if candidates.iter().any(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })) {
@@ -1938,7 +1943,82 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
19381943
body_def_id: LocalDefId,
19391944
err: &mut Diagnostic,
19401945
other: bool,
1946+
param_env: ty::ParamEnv<'tcx>,
19411947
) -> bool {
1948+
// If we have a single implementation, try to unify it with the trait ref
1949+
// that failed. This should uncover a better hint for what *is* implemented.
1950+
if let [single] = &impl_candidates {
1951+
if self.probe(|_| {
1952+
let ocx = ObligationCtxt::new(self);
1953+
let obligation_trait_ref = self.instantiate_binder_with_placeholders(trait_ref);
1954+
let impl_args = self.fresh_args_for_item(DUMMY_SP, single.impl_def_id);
1955+
let impl_trait_ref = ocx.normalize(
1956+
&ObligationCause::dummy(),
1957+
param_env,
1958+
ty::EarlyBinder::bind(single.trait_ref).instantiate(self.tcx, impl_args),
1959+
);
1960+
1961+
ocx.register_obligations(
1962+
self.tcx
1963+
.predicates_of(single.impl_def_id)
1964+
.instantiate(self.tcx, impl_args)
1965+
.into_iter()
1966+
.map(|(clause, _)| {
1967+
Obligation::new(self.tcx, ObligationCause::dummy(), param_env, clause)
1968+
}),
1969+
);
1970+
if !ocx.select_where_possible().is_empty() {
1971+
return false;
1972+
}
1973+
1974+
let mut terrs = vec![];
1975+
for (obligation_arg, impl_arg) in
1976+
std::iter::zip(obligation_trait_ref.args, impl_trait_ref.args)
1977+
{
1978+
if let Err(terr) =
1979+
ocx.eq(&ObligationCause::dummy(), param_env, impl_arg, obligation_arg)
1980+
{
1981+
terrs.push(terr);
1982+
}
1983+
if !ocx.select_where_possible().is_empty() {
1984+
return false;
1985+
}
1986+
}
1987+
1988+
// Literally nothing unified, just give up.
1989+
if terrs.len() == impl_trait_ref.args.len() {
1990+
return false;
1991+
}
1992+
1993+
let cand =
1994+
self.resolve_vars_if_possible(impl_trait_ref).fold_with(&mut BottomUpFolder {
1995+
tcx: self.tcx,
1996+
ty_op: |ty| ty,
1997+
lt_op: |lt| lt,
1998+
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
1999+
});
2000+
err.highlighted_help(vec![
2001+
(format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle),
2002+
("is".to_string(), Style::Highlight),
2003+
(" implemented for `".to_string(), Style::NoStyle),
2004+
(cand.self_ty().to_string(), Style::Highlight),
2005+
("`".to_string(), Style::NoStyle),
2006+
]);
2007+
2008+
if let [TypeError::Sorts(exp_found)] = &terrs[..] {
2009+
let exp_found = self.resolve_vars_if_possible(*exp_found);
2010+
err.help(format!(
2011+
"for that trait implementation, expected `{}`, found `{}`",
2012+
exp_found.expected, exp_found.found
2013+
));
2014+
}
2015+
2016+
true
2017+
}) {
2018+
return true;
2019+
}
2020+
}
2021+
19422022
let other = if other { "other " } else { "" };
19432023
let report = |candidates: Vec<TraitRef<'tcx>>, err: &mut Diagnostic| {
19442024
if candidates.is_empty() {
@@ -2062,9 +2142,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
20622142
})
20632143
.collect();
20642144
impl_candidates.sort_by_key(|cand| (cand.similarity, cand.trait_ref));
2145+
let mut impl_candidates: Vec<_> =
2146+
impl_candidates.into_iter().map(|cand| cand.trait_ref).collect();
20652147
impl_candidates.dedup();
20662148

2067-
report(impl_candidates.into_iter().map(|cand| cand.trait_ref).collect(), err)
2149+
report(impl_candidates, err)
20682150
}
20692151

20702152
fn report_similar_impl_candidates_for_root_obligation(
@@ -2108,6 +2190,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
21082190
body_def_id,
21092191
err,
21102192
true,
2193+
obligation.param_env,
21112194
);
21122195
}
21132196
}
@@ -2316,6 +2399,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
23162399
obligation.cause.body_id,
23172400
&mut err,
23182401
false,
2402+
obligation.param_env,
23192403
);
23202404
}
23212405
}
@@ -3051,6 +3135,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
30513135
body_def_id,
30523136
err,
30533137
true,
3138+
obligation.param_env,
30543139
) {
30553140
self.report_similar_impl_candidates_for_root_obligation(
30563141
&obligation,

tests/ui/const-generics/occurs-check/unused-substs-1.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `A<_>: Bar<_>` is not satisfied
44
LL | let _ = A;
55
| ^ the trait `Bar<_>` is not implemented for `A<_>`
66
|
7-
= help: the trait `Bar<N>` is implemented for `A<7>`
7+
= help: the trait `Bar<_>` is implemented for `A<7>`
88
note: required by a bound in `A`
99
--> $DIR/unused-substs-1.rs:9:11
1010
|

tests/ui/generic-const-items/unsatisfied-bounds.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ LL | let () = K::<()>;
1717
| ^^ the trait `From<()>` is not implemented for `Infallible`
1818
|
1919
= help: the trait `From<!>` is implemented for `Infallible`
20+
= help: for that trait implementation, expected `!`, found `()`
2021
note: required by a bound in `K`
2122
--> $DIR/unsatisfied-bounds.rs:12:17
2223
|
@@ -48,6 +49,7 @@ LL | let _ = <() as Trait<&'static str>>::B::<()>;
4849
| ^^ the trait `From<()>` is not implemented for `Infallible`
4950
|
5051
= help: the trait `From<!>` is implemented for `Infallible`
52+
= help: for that trait implementation, expected `!`, found `()`
5153
note: required by a bound in `Trait::B`
5254
--> $DIR/unsatisfied-bounds.rs:21:21
5355
|

tests/ui/impl-trait/issues/issue-62742.stderr

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
44
LL | WrongImpl::foo(0i32);
55
| ^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>`
66
|
7-
= help: the trait `Raw<[T]>` is implemented for `RawImpl<T>`
7+
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
88
note: required by a bound in `SafeImpl`
99
--> $DIR/issue-62742.rs:26:35
1010
|
@@ -42,7 +42,8 @@ error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied
4242
LL | WrongImpl::<()>::foo(0i32);
4343
| ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>`
4444
|
45-
= help: the trait `Raw<[T]>` is implemented for `RawImpl<T>`
45+
= help: the trait `Raw<[()]>` is implemented for `RawImpl<()>`
46+
= help: for that trait implementation, expected `[()]`, found `()`
4647
note: required by a bound in `SafeImpl`
4748
--> $DIR/issue-62742.rs:26:35
4849
|

tests/ui/indexing/index-help.stderr

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ LL | x[0i32];
55
| ^^^^ slice indices are of type `usize` or ranges of `usize`
66
|
77
= help: the trait `SliceIndex<[{integer}]>` is not implemented for `i32`
8-
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
8+
= help: the trait `SliceIndex<[{integer}]>` is implemented for `usize`
9+
= help: for that trait implementation, expected `usize`, found `i32`
910
= note: required for `Vec<{integer}>` to implement `Index<i32>`
1011

1112
error: aborting due to previous error

tests/ui/indexing/indexing-requires-a-uint.stderr

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ LL | [0][0u8];
55
| ^^^ slice indices are of type `usize` or ranges of `usize`
66
|
77
= help: the trait `SliceIndex<[{integer}]>` is not implemented for `u8`
8-
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
8+
= help: the trait `SliceIndex<[{integer}]>` is implemented for `usize`
9+
= help: for that trait implementation, expected `usize`, found `u8`
910
= note: required for `[{integer}]` to implement `Index<u8>`
1011

1112
error[E0308]: mismatched types

tests/ui/integral-indexing.stderr

+16-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ LL | v[3u8];
55
| ^^^ slice indices are of type `usize` or ranges of `usize`
66
|
77
= help: the trait `SliceIndex<[isize]>` is not implemented for `u8`
8-
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
8+
= help: the trait `SliceIndex<[isize]>` is implemented for `usize`
9+
= help: for that trait implementation, expected `usize`, found `u8`
910
= note: required for `Vec<isize>` to implement `Index<u8>`
1011

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

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

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

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

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

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

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

8189
error: aborting due to 8 previous errors

tests/ui/issues/issue-34334.stderr

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_rece
1919
| ^^^^^^^ value of type `Vec<(u32, _, _)>` cannot be built from `std::iter::Iterator<Item=()>`
2020
|
2121
= help: the trait `FromIterator<()>` is not implemented for `Vec<(u32, _, _)>`
22-
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
22+
= help: the trait `FromIterator<(u32, _, _)>` is implemented for `Vec<(u32, _, _)>`
23+
= help: for that trait implementation, expected `(u32, _, _)`, found `()`
2324
note: the method call chain might not have had the expected associated types
2425
--> $DIR/issue-34334.rs:5:43
2526
|

tests/ui/issues/issue-45801.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LL | req.get_ref::<Params>();
55
| ^^^^^^^ the trait `Plugin<i32>` is not implemented for `Params`
66
|
77
= help: the trait `Plugin<Foo>` is implemented for `Params`
8+
= help: for that trait implementation, expected `Foo`, found `i32`
89

910
error: aborting due to previous error
1011

tests/ui/issues/issue-66923-show-error-for-correct-call.stderr

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ LL | let x2: Vec<f64> = x1.into_iter().collect();
55
| ^^^^^^^ value of type `Vec<f64>` cannot be built from `std::iter::Iterator<Item=&f64>`
66
|
77
= help: the trait `FromIterator<&f64>` is not implemented for `Vec<f64>`
8-
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
8+
= help: the trait `FromIterator<f64>` is implemented for `Vec<f64>`
9+
= help: for that trait implementation, expected `f64`, found `&f64`
910
note: the method call chain might not have had the expected associated types
1011
--> $DIR/issue-66923-show-error-for-correct-call.rs:8:27
1112
|
@@ -25,7 +26,8 @@ LL | let x3 = x1.into_iter().collect::<Vec<f64>>();
2526
| required by a bound introduced by this call
2627
|
2728
= help: the trait `FromIterator<&f64>` is not implemented for `Vec<f64>`
28-
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
29+
= help: the trait `FromIterator<f64>` is implemented for `Vec<f64>`
30+
= help: for that trait implementation, expected `f64`, found `&f64`
2931
note: the method call chain might not have had the expected associated types
3032
--> $DIR/issue-66923-show-error-for-correct-call.rs:12:17
3133
|

tests/ui/iterators/invalid-iterator-chain.stderr

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ LL | i.collect()
55
| ^^^^^^^ value of type `Vec<X>` cannot be built from `std::iter::Iterator<Item=&X>`
66
|
77
= help: the trait `FromIterator<&X>` is not implemented for `Vec<X>`
8-
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
8+
= help: the trait `FromIterator<X>` is implemented for `Vec<X>`
9+
= help: for that trait implementation, expected `X`, found `&X`
910
note: the method call chain might not have had the expected associated types
1011
--> $DIR/invalid-iterator-chain.rs:4:26
1112
|
@@ -159,7 +160,8 @@ LL | let g: Vec<i32> = f.collect();
159160
| ^^^^^^^ value of type `Vec<i32>` cannot be built from `std::iter::Iterator<Item=()>`
160161
|
161162
= help: the trait `FromIterator<()>` is not implemented for `Vec<i32>`
162-
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
163+
= help: the trait `FromIterator<i32>` is implemented for `Vec<i32>`
164+
= help: for that trait implementation, expected `i32`, found `()`
163165
note: the method call chain might not have had the expected associated types
164166
--> $DIR/invalid-iterator-chain.rs:44:15
165167
|

tests/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LL | <E as From<_>>::from(never);
55
| ^ the trait `From<()>` is not implemented for `E`
66
|
77
= help: the trait `From<!>` is implemented for `E`
8+
= help: for that trait implementation, expected `!`, found `()`
89

910
error: aborting due to previous error
1011

tests/ui/on-unimplemented/impl-substs.stderr

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ LL | Foo::<usize>::foo((1i32, 1i32, 1i32));
77
| required by a bound introduced by this call
88
|
99
= help: the trait `Foo<usize>` is not implemented for `(i32, i32, i32)`
10-
= help: the trait `Foo<A>` is implemented for `(A, B, C)`
10+
= help: the trait `Foo<i32>` is implemented for `(i32, i32, i32)`
11+
= help: for that trait implementation, expected `i32`, found `usize`
1112

1213
error: aborting due to previous error
1314

tests/ui/on-unimplemented/on-impl.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ LL | Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
88
|
99
= help: the trait `Index<u32>` is not implemented for `[i32]`
1010
= help: the trait `Index<usize>` is implemented for `[i32]`
11+
= help: for that trait implementation, expected `usize`, found `u32`
1112

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

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

3033
error: aborting due to 3 previous errors
3134

0 commit comments

Comments
 (0)