Skip to content

Commit ef91519

Browse files
committed
Dedup logic and improve output for other types that impl trait
1 parent e2bba07 commit ef91519

File tree

47 files changed

+363
-357
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+363
-357
lines changed

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

+60-61
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use rustc_middle::traits::select::OverflowError;
3030
use rustc_middle::ty::error::ExpectedFound;
3131
use rustc_middle::ty::fold::TypeFolder;
3232
use rustc_middle::ty::{
33-
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable,
33+
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
3434
};
3535
use rustc_span::symbol::{kw, sym};
3636
use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP};
@@ -1756,6 +1756,60 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
17561756
trait_ref: ty::PolyTraitRef<'tcx>,
17571757
err: &mut Diagnostic,
17581758
) -> bool {
1759+
let report = |mut candidates: Vec<TraitRef<'_>>, err: &mut Diagnostic| {
1760+
candidates.sort();
1761+
candidates.dedup();
1762+
let len = candidates.len();
1763+
if candidates.len() == 0 {
1764+
return false;
1765+
}
1766+
let trait_ref = candidates[0];
1767+
if candidates.len() == 1 {
1768+
err.highlighted_help(vec![
1769+
(
1770+
format!(
1771+
"the trait `{}` is implemented for `",
1772+
trait_ref.print_only_trait_path()
1773+
),
1774+
Style::NoStyle,
1775+
),
1776+
(candidates[0].self_ty().to_string(), Style::Highlight),
1777+
("`".to_string(), Style::NoStyle),
1778+
]);
1779+
return true;
1780+
}
1781+
// Check if the trait is the same in all cases. If so, we'll only show the type.
1782+
// FIXME: there *has* to be a better way!
1783+
let mut traits: Vec<_> = candidates
1784+
.iter()
1785+
.map(|c| format!("{}", c).split(" as ").last().unwrap().to_string())
1786+
.collect();
1787+
traits.sort();
1788+
traits.dedup();
1789+
1790+
let mut candidates: Vec<String> = candidates
1791+
.into_iter()
1792+
.map(|c| {
1793+
if traits.len() == 1 {
1794+
format!("\n {}", c.self_ty())
1795+
} else {
1796+
format!("\n {}", c)
1797+
}
1798+
})
1799+
.collect();
1800+
1801+
candidates.sort();
1802+
candidates.dedup();
1803+
let end = if candidates.len() <= 9 { candidates.len() } else { 8 };
1804+
err.help(&format!(
1805+
"the following other types implement trait `{}`:{}{}",
1806+
trait_ref.print_only_trait_path(),
1807+
candidates[..end].join(""),
1808+
if len > 9 { format!("\nand {} others", len - 8) } else { String::new() }
1809+
));
1810+
true
1811+
};
1812+
17591813
let def_id = trait_ref.def_id();
17601814
if impl_candidates.is_empty() {
17611815
if self.tcx.trait_is_auto(def_id)
@@ -1765,7 +1819,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
17651819
// Mentioning implementers of `Copy`, `Debug` and friends is not useful.
17661820
return false;
17671821
}
1768-
let mut normalized_impl_candidates: Vec<_> = self
1822+
let normalized_impl_candidates: Vec<_> = self
17691823
.tcx
17701824
.all_impls(def_id)
17711825
// Ignore automatically derived impls and `!Trait` impls.
@@ -1776,54 +1830,19 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
17761830
.filter_map(|def_id| self.tcx.impl_trait_ref(def_id))
17771831
// Avoid mentioning type parameters.
17781832
.filter(|trait_ref| !matches!(trait_ref.self_ty().kind(), ty::Param(_)))
1779-
.map(|trait_ref| format!("\n {}", trait_ref.self_ty()))
17801833
.collect();
1781-
normalized_impl_candidates.sort();
1782-
normalized_impl_candidates.dedup();
1783-
let len = normalized_impl_candidates.len();
1784-
if len == 0 {
1785-
return false;
1786-
}
1787-
if len == 1 {
1788-
err.highlighted_help(vec![
1789-
(
1790-
format!(
1791-
"the trait `{}` is implemented for `",
1792-
trait_ref.print_only_trait_path()
1793-
),
1794-
Style::NoStyle,
1795-
),
1796-
(normalized_impl_candidates[0].trim().to_string(), Style::Highlight),
1797-
("`".to_string(), Style::NoStyle),
1798-
]);
1799-
return true;
1800-
}
1801-
let end = if normalized_impl_candidates.len() <= 9 {
1802-
normalized_impl_candidates.len()
1803-
} else {
1804-
8
1805-
};
1806-
err.help(&format!(
1807-
"the following other types implement trait `{}`:{}{}",
1808-
trait_ref.print_only_trait_path(),
1809-
normalized_impl_candidates[..end].join(""),
1810-
if len > 9 { format!("\nand {} others", len - 8) } else { String::new() }
1811-
));
1812-
return true;
1834+
return report(normalized_impl_candidates, err);
18131835
}
18141836

1815-
let len = impl_candidates.len();
1816-
let end = if impl_candidates.len() <= 9 { impl_candidates.len() } else { 8 };
1817-
18181837
let normalize = |candidate| {
18191838
self.tcx.infer_ctxt().enter(|ref infcx| {
18201839
let normalized = infcx
18211840
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
18221841
.normalize(candidate)
18231842
.ok();
18241843
match normalized {
1825-
Some(normalized) => format!("\n {}", normalized.value),
1826-
None => format!("\n {}", candidate),
1844+
Some(normalized) => normalized.value,
1845+
None => candidate,
18271846
}
18281847
})
18291848
};
@@ -1834,7 +1853,6 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
18341853
//
18351854
// Prefer more similar candidates first, then sort lexicographically
18361855
// by their normalized string representation.
1837-
let first_candidate = impl_candidates.get(0).map(|candidate| candidate.trait_ref);
18381856
let mut normalized_impl_candidates_and_similarities = impl_candidates
18391857
.into_iter()
18401858
.map(|ImplCandidate { trait_ref, similarity }| {
@@ -1850,26 +1868,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
18501868
.map(|(_, normalized)| normalized)
18511869
.collect::<Vec<_>>();
18521870

1853-
if normalized_impl_candidates.len() == 1 {
1854-
err.highlighted_help(vec![
1855-
(
1856-
format!(
1857-
"the trait `{}` is implemented for `",
1858-
first_candidate.unwrap().print_only_trait_path()
1859-
),
1860-
Style::NoStyle,
1861-
),
1862-
(first_candidate.unwrap().self_ty().to_string(), Style::Highlight),
1863-
("`".to_string(), Style::NoStyle),
1864-
]);
1865-
} else {
1866-
err.help(&format!(
1867-
"the following implementations were found:{}{}",
1868-
normalized_impl_candidates[..end].join(""),
1869-
if len > 9 { format!("\nand {} others", len - 8) } else { String::new() }
1870-
));
1871-
}
1872-
true
1871+
report(normalized_impl_candidates, err)
18731872
}
18741873

18751874
/// Gets the parent trait chain start

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

+5-2
Original file line numberDiff line numberDiff line change
@@ -557,8 +557,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
557557
}
558558
} else if real_trait_pred != trait_pred {
559559
// This branch addresses #87437.
560-
let obligation =
561-
self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred, base_ty);
560+
let obligation = self.mk_trait_obligation_with_new_self_ty(
561+
param_env,
562+
real_trait_pred,
563+
base_ty,
564+
);
562565
if self.predicate_may_hold(&obligation) {
563566
err.span_suggestion_verbose(
564567
span.shrink_to_lo(),

src/test/ui/binop/binop-mul-i32-f32.stderr

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ LL | x * y
55
| ^ no implementation for `i32 * f32`
66
|
77
= help: the trait `Mul<f32>` is not implemented for `i32`
8-
= help: the following implementations were found:
9-
<&'a i32 as Mul<i32>>
10-
<&i32 as Mul<&i32>>
11-
<i32 as Mul<&i32>>
12-
<i32 as Mul>
8+
= help: the following other types implement trait `Mul`:
139
<&'a f32 as Mul<f32>>
1410
<&'a f64 as Mul<f64>>
1511
<&'a i128 as Mul<i128>>
1612
<&'a i16 as Mul<i16>>
13+
<&'a i32 as Mul<i32>>
14+
<&'a i64 as Mul<i64>>
15+
<&'a i8 as Mul<i8>>
16+
<&'a isize as Mul<isize>>
1717
and 49 others
1818

1919
error: aborting due to previous error

src/test/ui/binop/issue-77910-1.stderr

+9-9
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ LL | assert_eq!(foo, y);
1616
| ^^^^^^^^^^^^^^^^^^ `for<'r> fn(&'r i32) -> &'r i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
1717
|
1818
= help: the trait `Debug` is not implemented for `for<'r> fn(&'r i32) -> &'r i32 {foo}`
19-
= help: the following implementations were found:
20-
<extern "C" fn() -> Ret as Debug>
21-
<extern "C" fn(A) -> Ret as Debug>
22-
<extern "C" fn(A, ...) -> Ret as Debug>
23-
<extern "C" fn(A, B) -> Ret as Debug>
24-
<extern "C" fn(A, B, ...) -> Ret as Debug>
25-
<extern "C" fn(A, B, C) -> Ret as Debug>
26-
<extern "C" fn(A, B, C, ...) -> Ret as Debug>
27-
<extern "C" fn(A, B, C, D) -> Ret as Debug>
19+
= help: the following other types implement trait `Debug`:
20+
extern "C" fn() -> Ret
21+
extern "C" fn(A) -> Ret
22+
extern "C" fn(A, ...) -> Ret
23+
extern "C" fn(A, B) -> Ret
24+
extern "C" fn(A, B, ...) -> Ret
25+
extern "C" fn(A, B, C) -> Ret
26+
extern "C" fn(A, B, C, ...) -> Ret
27+
extern "C" fn(A, B, C, D) -> Ret
2828
and 68 others
2929
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
3030

src/test/ui/binop/shift-various-bad-types.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | 22 >> p.char;
55
| ^^ no implementation for `{integer} >> char`
66
|
77
= help: the trait `Shr<char>` is not implemented for `{integer}`
8-
= help: the following implementations were found:
8+
= help: the following other types implement trait `Shr`:
99
<&'a i128 as Shr<i128>>
1010
<&'a i128 as Shr<i16>>
1111
<&'a i128 as Shr<i32>>
@@ -23,7 +23,7 @@ LL | 22 >> p.str;
2323
| ^^ no implementation for `{integer} >> &str`
2424
|
2525
= help: the trait `Shr<&str>` is not implemented for `{integer}`
26-
= help: the following implementations were found:
26+
= help: the following other types implement trait `Shr`:
2727
<&'a i128 as Shr<i128>>
2828
<&'a i128 as Shr<i16>>
2929
<&'a i128 as Shr<i32>>
@@ -41,7 +41,7 @@ LL | 22 >> p;
4141
| ^^ no implementation for `{integer} >> &Panolpy`
4242
|
4343
= help: the trait `Shr<&Panolpy>` is not implemented for `{integer}`
44-
= help: the following implementations were found:
44+
= help: the following other types implement trait `Shr`:
4545
<&'a i128 as Shr<i128>>
4646
<&'a i128 as Shr<i16>>
4747
<&'a i128 as Shr<i32>>

src/test/ui/chalkify/chalk_initial_program.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ error[E0277]: the trait bound `f32: Foo` is not satisfied
44
LL | gimme::<f32>();
55
| ^^^ the trait `Foo` is not implemented for `f32`
66
|
7-
= help: the following implementations were found:
8-
<i32 as Foo>
9-
<u32 as Foo>
7+
= help: the following other types implement trait `Foo`:
8+
i32
9+
u32
1010
note: required by a bound in `gimme`
1111
--> $DIR/chalk_initial_program.rs:9:13
1212
|

src/test/ui/chalkify/type_inference.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ LL | only_bar(x);
66
| |
77
| required by a bound introduced by this call
88
|
9-
= help: the following implementations were found:
10-
<i32 as Bar>
11-
<u32 as Bar>
9+
= help: the following other types implement trait `Bar`:
10+
i32
11+
u32
1212
note: required by a bound in `only_bar`
1313
--> $DIR/type_inference.rs:12:16
1414
|

src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ error[E0277]: the trait bound `u32: Traitor<N, N>` is not satisfied
2525
LL | fn uwu<const N: u8>() -> impl Traitor<N> {
2626
| ^^^^^^^^^^^^^^^ the trait `Traitor<N, N>` is not implemented for `u32`
2727
|
28-
= help: the following implementations were found:
28+
= help: the following other types implement trait `Traitor<N, 2_u8>`:
2929
<u32 as Traitor<N, 2_u8>>
3030
<u64 as Traitor<1_u8, 2_u8>>
3131

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

5757
error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
5858
--> $DIR/rp_impl_trait_fail.rs:24:26

src/test/ui/const-generics/exhaustive-value.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `(): Foo<N>` is not satisfied
44
LL | <() as Foo<N>>::test()
55
| ^^^^^^^^^^^^^^^^^^^^ the trait `Foo<N>` is not implemented for `()`
66
|
7-
= help: the following implementations were found:
7+
= help: the following other types implement trait `Foo<0_u8>`:
88
<() as Foo<0_u8>>
99
<() as Foo<100_u8>>
1010
<() as Foo<101_u8>>

src/test/ui/const-generics/issues/issue-67185-2.stderr

+18-18
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
44
LL | <u8 as Baz>::Quaks: Bar,
55
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `[u16; 3]`
66
|
7-
= help: the following implementations were found:
8-
<[[u16; 3]; 3] as Bar>
9-
<[u16; 4] as Bar>
7+
= help: the following other types implement trait `Bar`:
8+
[[u16; 3]; 3]
9+
[u16; 4]
1010
= help: see issue #48214
1111
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
1212

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

@@ -28,9 +28,9 @@ error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
2828
LL | impl Foo for FooImpl {}
2929
| ^^^ the trait `Bar` is not implemented for `[u16; 3]`
3030
|
31-
= help: the following implementations were found:
32-
<[[u16; 3]; 3] as Bar>
33-
<[u16; 4] as Bar>
31+
= help: the following other types implement trait `Bar`:
32+
[[u16; 3]; 3]
33+
[u16; 4]
3434
note: required by a bound in `Foo`
3535
--> $DIR/issue-67185-2.rs:15:25
3636
|
@@ -46,9 +46,9 @@ error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
4646
LL | impl Foo for FooImpl {}
4747
| ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]`
4848
|
49-
= help: the following implementations were found:
50-
<[[u16; 3]; 3] as Bar>
51-
<[u16; 4] as Bar>
49+
= help: the following other types implement trait `Bar`:
50+
[[u16; 3]; 3]
51+
[u16; 4]
5252
note: required by a bound in `Foo`
5353
--> $DIR/issue-67185-2.rs:14:30
5454
|
@@ -64,9 +64,9 @@ error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
6464
LL | fn f(_: impl Foo) {}
6565
| ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]`
6666
|
67-
= help: the following implementations were found:
68-
<[[u16; 3]; 3] as Bar>
69-
<[u16; 4] as Bar>
67+
= help: the following other types implement trait `Bar`:
68+
[[u16; 3]; 3]
69+
[u16; 4]
7070
note: required by a bound in `Foo`
7171
--> $DIR/issue-67185-2.rs:14:30
7272
|
@@ -82,9 +82,9 @@ error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
8282
LL | fn f(_: impl Foo) {}
8383
| ^^^ the trait `Bar` is not implemented for `[u16; 3]`
8484
|
85-
= help: the following implementations were found:
86-
<[[u16; 3]; 3] as Bar>
87-
<[u16; 4] as Bar>
85+
= help: the following other types implement trait `Bar`:
86+
[[u16; 3]; 3]
87+
[u16; 4]
8888
note: required by a bound in `Foo`
8989
--> $DIR/issue-67185-2.rs:15:25
9090
|

0 commit comments

Comments
 (0)