Skip to content

Commit

Permalink
Dedup logic and improve output for other types that impl trait
Browse files Browse the repository at this point in the history
  • Loading branch information
estebank committed Apr 4, 2022
1 parent e2bba07 commit ef91519
Show file tree
Hide file tree
Showing 47 changed files with 363 additions and 357 deletions.
121 changes: 60 additions & 61 deletions compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::fold::TypeFolder;
use rustc_middle::ty::{
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable,
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
};
use rustc_span::symbol::{kw, sym};
use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP};
Expand Down Expand Up @@ -1756,6 +1756,60 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
trait_ref: ty::PolyTraitRef<'tcx>,
err: &mut Diagnostic,
) -> bool {
let report = |mut candidates: Vec<TraitRef<'_>>, err: &mut Diagnostic| {
candidates.sort();
candidates.dedup();
let len = candidates.len();
if candidates.len() == 0 {
return false;
}
let trait_ref = candidates[0];
if candidates.len() == 1 {
err.highlighted_help(vec![
(
format!(
"the trait `{}` is implemented for `",
trait_ref.print_only_trait_path()
),
Style::NoStyle,
),
(candidates[0].self_ty().to_string(), Style::Highlight),
("`".to_string(), Style::NoStyle),
]);
return true;
}
// Check if the trait is the same in all cases. If so, we'll only show the type.
// FIXME: there *has* to be a better way!
let mut traits: Vec<_> = candidates
.iter()
.map(|c| format!("{}", c).split(" as ").last().unwrap().to_string())
.collect();
traits.sort();
traits.dedup();

let mut candidates: Vec<String> = candidates
.into_iter()
.map(|c| {
if traits.len() == 1 {
format!("\n {}", c.self_ty())
} else {
format!("\n {}", c)
}
})
.collect();

candidates.sort();
candidates.dedup();
let end = if candidates.len() <= 9 { candidates.len() } else { 8 };
err.help(&format!(
"the following other types implement trait `{}`:{}{}",
trait_ref.print_only_trait_path(),
candidates[..end].join(""),
if len > 9 { format!("\nand {} others", len - 8) } else { String::new() }
));
true
};

let def_id = trait_ref.def_id();
if impl_candidates.is_empty() {
if self.tcx.trait_is_auto(def_id)
Expand All @@ -1765,7 +1819,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
// Mentioning implementers of `Copy`, `Debug` and friends is not useful.
return false;
}
let mut normalized_impl_candidates: Vec<_> = self
let normalized_impl_candidates: Vec<_> = self
.tcx
.all_impls(def_id)
// Ignore automatically derived impls and `!Trait` impls.
Expand All @@ -1776,54 +1830,19 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
.filter_map(|def_id| self.tcx.impl_trait_ref(def_id))
// Avoid mentioning type parameters.
.filter(|trait_ref| !matches!(trait_ref.self_ty().kind(), ty::Param(_)))
.map(|trait_ref| format!("\n {}", trait_ref.self_ty()))
.collect();
normalized_impl_candidates.sort();
normalized_impl_candidates.dedup();
let len = normalized_impl_candidates.len();
if len == 0 {
return false;
}
if len == 1 {
err.highlighted_help(vec![
(
format!(
"the trait `{}` is implemented for `",
trait_ref.print_only_trait_path()
),
Style::NoStyle,
),
(normalized_impl_candidates[0].trim().to_string(), Style::Highlight),
("`".to_string(), Style::NoStyle),
]);
return true;
}
let end = if normalized_impl_candidates.len() <= 9 {
normalized_impl_candidates.len()
} else {
8
};
err.help(&format!(
"the following other types implement trait `{}`:{}{}",
trait_ref.print_only_trait_path(),
normalized_impl_candidates[..end].join(""),
if len > 9 { format!("\nand {} others", len - 8) } else { String::new() }
));
return true;
return report(normalized_impl_candidates, err);
}

let len = impl_candidates.len();
let end = if impl_candidates.len() <= 9 { impl_candidates.len() } else { 8 };

let normalize = |candidate| {
self.tcx.infer_ctxt().enter(|ref infcx| {
let normalized = infcx
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
.normalize(candidate)
.ok();
match normalized {
Some(normalized) => format!("\n {}", normalized.value),
None => format!("\n {}", candidate),
Some(normalized) => normalized.value,
None => candidate,
}
})
};
Expand All @@ -1834,7 +1853,6 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
//
// Prefer more similar candidates first, then sort lexicographically
// by their normalized string representation.
let first_candidate = impl_candidates.get(0).map(|candidate| candidate.trait_ref);
let mut normalized_impl_candidates_and_similarities = impl_candidates
.into_iter()
.map(|ImplCandidate { trait_ref, similarity }| {
Expand All @@ -1850,26 +1868,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
.map(|(_, normalized)| normalized)
.collect::<Vec<_>>();

if normalized_impl_candidates.len() == 1 {
err.highlighted_help(vec![
(
format!(
"the trait `{}` is implemented for `",
first_candidate.unwrap().print_only_trait_path()
),
Style::NoStyle,
),
(first_candidate.unwrap().self_ty().to_string(), Style::Highlight),
("`".to_string(), Style::NoStyle),
]);
} else {
err.help(&format!(
"the following implementations were found:{}{}",
normalized_impl_candidates[..end].join(""),
if len > 9 { format!("\nand {} others", len - 8) } else { String::new() }
));
}
true
report(normalized_impl_candidates, err)
}

/// Gets the parent trait chain start
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -557,8 +557,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}
} else if real_trait_pred != trait_pred {
// This branch addresses #87437.
let obligation =
self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred, base_ty);
let obligation = self.mk_trait_obligation_with_new_self_ty(
param_env,
real_trait_pred,
base_ty,
);
if self.predicate_may_hold(&obligation) {
err.span_suggestion_verbose(
span.shrink_to_lo(),
Expand Down
10 changes: 5 additions & 5 deletions src/test/ui/binop/binop-mul-i32-f32.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ LL | x * y
| ^ no implementation for `i32 * f32`
|
= help: the trait `Mul<f32>` is not implemented for `i32`
= help: the following implementations were found:
<&'a i32 as Mul<i32>>
<&i32 as Mul<&i32>>
<i32 as Mul<&i32>>
<i32 as Mul>
= help: the following other types implement trait `Mul`:
<&'a f32 as Mul<f32>>
<&'a f64 as Mul<f64>>
<&'a i128 as Mul<i128>>
<&'a i16 as Mul<i16>>
<&'a i32 as Mul<i32>>
<&'a i64 as Mul<i64>>
<&'a i8 as Mul<i8>>
<&'a isize as Mul<isize>>
and 49 others

error: aborting due to previous error
Expand Down
18 changes: 9 additions & 9 deletions src/test/ui/binop/issue-77910-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ LL | assert_eq!(foo, y);
| ^^^^^^^^^^^^^^^^^^ `for<'r> fn(&'r i32) -> &'r i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
= help: the trait `Debug` is not implemented for `for<'r> fn(&'r i32) -> &'r i32 {foo}`
= help: the following implementations were found:
<extern "C" fn() -> Ret as Debug>
<extern "C" fn(A) -> Ret as Debug>
<extern "C" fn(A, ...) -> Ret as Debug>
<extern "C" fn(A, B) -> Ret as Debug>
<extern "C" fn(A, B, ...) -> Ret as Debug>
<extern "C" fn(A, B, C) -> Ret as Debug>
<extern "C" fn(A, B, C, ...) -> Ret as Debug>
<extern "C" fn(A, B, C, D) -> Ret as Debug>
= help: the following other types implement trait `Debug`:
extern "C" fn() -> Ret
extern "C" fn(A) -> Ret
extern "C" fn(A, ...) -> Ret
extern "C" fn(A, B) -> Ret
extern "C" fn(A, B, ...) -> Ret
extern "C" fn(A, B, C) -> Ret
extern "C" fn(A, B, C, ...) -> Ret
extern "C" fn(A, B, C, D) -> Ret
and 68 others
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)

Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/binop/shift-various-bad-types.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ LL | 22 >> p.char;
| ^^ no implementation for `{integer} >> char`
|
= help: the trait `Shr<char>` is not implemented for `{integer}`
= help: the following implementations were found:
= help: the following other types implement trait `Shr`:
<&'a i128 as Shr<i128>>
<&'a i128 as Shr<i16>>
<&'a i128 as Shr<i32>>
Expand All @@ -23,7 +23,7 @@ LL | 22 >> p.str;
| ^^ no implementation for `{integer} >> &str`
|
= help: the trait `Shr<&str>` is not implemented for `{integer}`
= help: the following implementations were found:
= help: the following other types implement trait `Shr`:
<&'a i128 as Shr<i128>>
<&'a i128 as Shr<i16>>
<&'a i128 as Shr<i32>>
Expand All @@ -41,7 +41,7 @@ LL | 22 >> p;
| ^^ no implementation for `{integer} >> &Panolpy`
|
= help: the trait `Shr<&Panolpy>` is not implemented for `{integer}`
= help: the following implementations were found:
= help: the following other types implement trait `Shr`:
<&'a i128 as Shr<i128>>
<&'a i128 as Shr<i16>>
<&'a i128 as Shr<i32>>
Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/chalkify/chalk_initial_program.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ error[E0277]: the trait bound `f32: Foo` is not satisfied
LL | gimme::<f32>();
| ^^^ the trait `Foo` is not implemented for `f32`
|
= help: the following implementations were found:
<i32 as Foo>
<u32 as Foo>
= help: the following other types implement trait `Foo`:
i32
u32
note: required by a bound in `gimme`
--> $DIR/chalk_initial_program.rs:9:13
|
Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/chalkify/type_inference.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ LL | only_bar(x);
| |
| required by a bound introduced by this call
|
= help: the following implementations were found:
<i32 as Bar>
<u32 as Bar>
= help: the following other types implement trait `Bar`:
i32
u32
note: required by a bound in `only_bar`
--> $DIR/type_inference.rs:12:16
|
Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ error[E0277]: the trait bound `u32: Traitor<N, N>` is not satisfied
LL | fn uwu<const N: u8>() -> impl Traitor<N> {
| ^^^^^^^^^^^^^^^ the trait `Traitor<N, N>` is not implemented for `u32`
|
= help: the following implementations were found:
= help: the following other types implement trait `Traitor<N, 2_u8>`:
<u32 as Traitor<N, 2_u8>>
<u64 as Traitor<1_u8, 2_u8>>

Expand All @@ -50,9 +50,9 @@ error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
LL | fn owo() -> impl Traitor {
| ^^^^^^^^^^^^ the trait `Traitor<1_u8, 1_u8>` is not implemented for `u64`
|
= help: the following implementations were found:
<u64 as Traitor<1_u8, 2_u8>>
= help: the following other types implement trait `Traitor<N, 2_u8>`:
<u32 as Traitor<N, 2_u8>>
<u64 as Traitor<1_u8, 2_u8>>

error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
--> $DIR/rp_impl_trait_fail.rs:24:26
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/const-generics/exhaustive-value.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error[E0277]: the trait bound `(): Foo<N>` is not satisfied
LL | <() as Foo<N>>::test()
| ^^^^^^^^^^^^^^^^^^^^ the trait `Foo<N>` is not implemented for `()`
|
= help: the following implementations were found:
= help: the following other types implement trait `Foo<0_u8>`:
<() as Foo<0_u8>>
<() as Foo<100_u8>>
<() as Foo<101_u8>>
Expand Down
36 changes: 18 additions & 18 deletions src/test/ui/const-generics/issues/issue-67185-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
LL | <u8 as Baz>::Quaks: Bar,
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `[u16; 3]`
|
= help: the following implementations were found:
<[[u16; 3]; 3] as Bar>
<[u16; 4] as Bar>
= help: the following other types implement trait `Bar`:
[[u16; 3]; 3]
[u16; 4]
= help: see issue #48214
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable

Expand All @@ -16,9 +16,9 @@ error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
LL | [<u8 as Baz>::Quaks; 2]: Bar,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]`
|
= help: the following implementations were found:
<[[u16; 3]; 3] as Bar>
<[u16; 4] as Bar>
= help: the following other types implement trait `Bar`:
[[u16; 3]; 3]
[u16; 4]
= help: see issue #48214
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable

Expand All @@ -28,9 +28,9 @@ error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
LL | impl Foo for FooImpl {}
| ^^^ the trait `Bar` is not implemented for `[u16; 3]`
|
= help: the following implementations were found:
<[[u16; 3]; 3] as Bar>
<[u16; 4] as Bar>
= help: the following other types implement trait `Bar`:
[[u16; 3]; 3]
[u16; 4]
note: required by a bound in `Foo`
--> $DIR/issue-67185-2.rs:15:25
|
Expand All @@ -46,9 +46,9 @@ error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
LL | impl Foo for FooImpl {}
| ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]`
|
= help: the following implementations were found:
<[[u16; 3]; 3] as Bar>
<[u16; 4] as Bar>
= help: the following other types implement trait `Bar`:
[[u16; 3]; 3]
[u16; 4]
note: required by a bound in `Foo`
--> $DIR/issue-67185-2.rs:14:30
|
Expand All @@ -64,9 +64,9 @@ error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
LL | fn f(_: impl Foo) {}
| ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]`
|
= help: the following implementations were found:
<[[u16; 3]; 3] as Bar>
<[u16; 4] as Bar>
= help: the following other types implement trait `Bar`:
[[u16; 3]; 3]
[u16; 4]
note: required by a bound in `Foo`
--> $DIR/issue-67185-2.rs:14:30
|
Expand All @@ -82,9 +82,9 @@ error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
LL | fn f(_: impl Foo) {}
| ^^^ the trait `Bar` is not implemented for `[u16; 3]`
|
= help: the following implementations were found:
<[[u16; 3]; 3] as Bar>
<[u16; 4] as Bar>
= help: the following other types implement trait `Bar`:
[[u16; 3]; 3]
[u16; 4]
note: required by a bound in `Foo`
--> $DIR/issue-67185-2.rs:15:25
|
Expand Down
Loading

0 comments on commit ef91519

Please sign in to comment.