Skip to content

Commit 6f6a43f

Browse files
committed
Auto merge of #145640 - estebank:point-at-impl-e0277, r=nnethercote
When a trait isn't implemented, but another similar impl is found, point at it ``` error[E0277]: the trait bound `u32: Trait` is not satisfied --> $DIR/trait_objects_fail.rs:26:9 | LL | foo(&10_u32); | ^^^^^^^ the trait `Trait` is not implemented for `u32` | help: the trait `Trait<12>` is not implemented for `u32` but trait `Trait<2>` is implemented for it --> $DIR/trait_objects_fail.rs:7:1 | LL | impl Trait<2> for u32 {} | ^^^^^^^^^^^^^^^^^^^^^ = note: required for the cast from `&u32` to `&dyn Trait` ``` Pointing at the `impl` definition that *could* apply given a different self type is *particularly* useful when it has a blanket self type, as it might not be obvious and is not trivially greppable: ``` error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied --> $DIR/issue-62742.rs:4:5 | LL | WrongImpl::foo(0i32); | ^^^^^^^^^ unsatisfied trait bound | help: the trait `Raw<_>` is not implemented for `RawImpl<_>` but trait `Raw<[_]>` is implemented for it --> $DIR/issue-62742.rs:29:1 | LL | impl<T> Raw<[T]> for RawImpl<T> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `SafeImpl` --> $DIR/issue-62742.rs:33:35 | LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>); | ^^^^^^ required by this bound in `SafeImpl` ```
2 parents f2824da + 473078e commit 6f6a43f

File tree

154 files changed

+1753
-638
lines changed

Some content is hidden

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

154 files changed

+1753
-638
lines changed

compiler/rustc_errors/src/emitter.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,16 +1526,17 @@ impl HumanEmitter {
15261526
label_width += 2;
15271527
}
15281528
let mut line = 0;
1529+
let mut pad = false;
15291530
for (text, style) in msgs.iter() {
15301531
let text =
15311532
self.translator.translate_message(text, args).map_err(Report::new).unwrap();
15321533
// Account for newlines to align output to its label.
1533-
for text in normalize_whitespace(&text).lines() {
1534+
for text in normalize_whitespace(&text).split('\n') {
15341535
buffer.append(
15351536
line,
15361537
&format!(
15371538
"{}{}",
1538-
if line == 0 { String::new() } else { " ".repeat(label_width) },
1539+
if pad { " ".repeat(label_width) } else { String::new() },
15391540
text
15401541
),
15411542
match style {
@@ -1544,7 +1545,9 @@ impl HumanEmitter {
15441545
},
15451546
);
15461547
line += 1;
1548+
pad = true;
15471549
}
1550+
pad = false;
15481551
// We add lines above, but if the last line has no explicit newline (which would
15491552
// yield an empty line), then we revert one line up to continue with the next
15501553
// styled text chunk on the same line as the last one from the prior one. Otherwise

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

Lines changed: 77 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1862,13 +1862,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
18621862
// ignore `do_not_recommend` items
18631863
.filter(|def_id| !self.tcx.do_not_recommend_impl(*def_id))
18641864
// Ignore automatically derived impls and `!Trait` impls.
1865-
.filter_map(|def_id| self.tcx.impl_trait_header(def_id))
1866-
.filter_map(|header| {
1865+
.filter_map(|def_id| self.tcx.impl_trait_header(def_id).map(|h| (h, def_id)))
1866+
.filter_map(|(header, def_id)| {
18671867
(header.polarity != ty::ImplPolarity::Negative
18681868
|| self.tcx.is_automatically_derived(def_id))
1869-
.then(|| header.trait_ref.instantiate_identity())
1869+
.then(|| (header.trait_ref.instantiate_identity(), def_id))
18701870
})
1871-
.filter(|trait_ref| {
1871+
.filter(|(trait_ref, _)| {
18721872
let self_ty = trait_ref.self_ty();
18731873
// Avoid mentioning type parameters.
18741874
if let ty::Param(_) = self_ty.kind() {
@@ -1886,7 +1886,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
18861886
})
18871887
.collect();
18881888

1889-
impl_candidates.sort_by_key(|tr| tr.to_string());
1889+
impl_candidates.sort_by_key(|(tr, _)| tr.to_string());
18901890
impl_candidates.dedup();
18911891
impl_candidates
18921892
};
@@ -1914,7 +1914,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
19141914
let candidates = if impl_candidates.is_empty() {
19151915
alternative_candidates(trait_def_id)
19161916
} else {
1917-
impl_candidates.into_iter().map(|cand| cand.trait_ref).collect()
1917+
impl_candidates.into_iter().map(|cand| (cand.trait_ref, cand.impl_def_id)).collect()
19181918
};
19191919
let mut span: MultiSpan = self.tcx.def_span(trait_def_id).into();
19201920
span.push_span_label(self.tcx.def_span(trait_def_id), "this is the required trait");
@@ -1946,7 +1946,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
19461946
self.tcx.def_span(found_type),
19471947
"this type doesn't implement the required trait",
19481948
);
1949-
for trait_ref in candidates {
1949+
for (trait_ref, _) in candidates {
19501950
if let ty::Adt(def, _) = trait_ref.self_ty().peel_refs().kind()
19511951
&& let candidate_def_id = def.did()
19521952
&& let Some(name) = self.tcx.opt_item_name(candidate_def_id)
@@ -2133,7 +2133,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
21332133
msg.extend(types.1.0);
21342134
msg.push(StringPart::normal("`"));
21352135
}
2136-
err.highlighted_help(msg);
2136+
err.highlighted_span_help(self.tcx.def_span(single.impl_def_id), msg);
21372137

21382138
if let [TypeError::Sorts(exp_found)] = &terrs[..] {
21392139
let exp_found = self.resolve_vars_if_possible(*exp_found);
@@ -2159,12 +2159,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
21592159
}
21602160

21612161
let other = if other { "other " } else { "" };
2162-
let report = |mut candidates: Vec<TraitRef<'tcx>>, err: &mut Diag<'_>| {
2163-
candidates.retain(|tr| !tr.references_error());
2162+
let report = |mut candidates: Vec<(TraitRef<'tcx>, DefId)>, err: &mut Diag<'_>| {
2163+
candidates.retain(|(tr, _)| !tr.references_error());
21642164
if candidates.is_empty() {
21652165
return false;
21662166
}
2167-
if let &[cand] = &candidates[..] {
2167+
if let &[(cand, def_id)] = &candidates[..] {
21682168
if self.tcx.is_diagnostic_item(sym::FromResidual, cand.def_id)
21692169
&& !self.tcx.features().enabled(sym::try_trait_v2)
21702170
{
@@ -2180,56 +2180,87 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
21802180
};
21812181
let trait_ = self.tcx.short_string(cand.print_trait_sugared(), err.long_ty_path());
21822182
let self_ty = self.tcx.short_string(cand.self_ty(), err.long_ty_path());
2183-
err.highlighted_help(vec![
2184-
StringPart::normal(format!("the trait `{trait_}` ",)),
2185-
StringPart::highlighted("is"),
2186-
StringPart::normal(desc),
2187-
StringPart::highlighted(self_ty),
2188-
StringPart::normal("`"),
2189-
StringPart::normal(mention_castable),
2190-
]);
2183+
err.highlighted_span_help(
2184+
self.tcx.def_span(def_id),
2185+
vec![
2186+
StringPart::normal(format!("the trait `{trait_}` ",)),
2187+
StringPart::highlighted("is"),
2188+
StringPart::normal(desc),
2189+
StringPart::highlighted(self_ty),
2190+
StringPart::normal("`"),
2191+
StringPart::normal(mention_castable),
2192+
],
2193+
);
21912194
return true;
21922195
}
2193-
let trait_ref = TraitRef::identity(self.tcx, candidates[0].def_id);
2196+
let trait_ref = TraitRef::identity(self.tcx, candidates[0].0.def_id);
21942197
// Check if the trait is the same in all cases. If so, we'll only show the type.
21952198
let mut traits: Vec<_> =
2196-
candidates.iter().map(|c| c.print_only_trait_path().to_string()).collect();
2199+
candidates.iter().map(|(c, _)| c.print_only_trait_path().to_string()).collect();
21972200
traits.sort();
21982201
traits.dedup();
21992202
// FIXME: this could use a better heuristic, like just checking
22002203
// that args[1..] is the same.
22012204
let all_traits_equal = traits.len() == 1;
22022205

2203-
let candidates: Vec<String> = candidates
2204-
.into_iter()
2205-
.map(|c| {
2206-
if all_traits_equal {
2207-
format!("\n {}", self.tcx.short_string(c.self_ty(), err.long_ty_path()))
2208-
} else {
2209-
format!(
2210-
"\n `{}` implements `{}`",
2211-
self.tcx.short_string(c.self_ty(), err.long_ty_path()),
2212-
self.tcx.short_string(c.print_only_trait_path(), err.long_ty_path()),
2213-
)
2214-
}
2215-
})
2216-
.collect();
2217-
22182206
let end = if candidates.len() <= 9 || self.tcx.sess.opts.verbose {
22192207
candidates.len()
22202208
} else {
22212209
8
22222210
};
2223-
err.help(format!(
2224-
"the following {other}types implement trait `{}`:{}{}",
2225-
trait_ref.print_trait_sugared(),
2226-
candidates[..end].join(""),
2227-
if candidates.len() > 9 && !self.tcx.sess.opts.verbose {
2228-
format!("\nand {} others", candidates.len() - 8)
2229-
} else {
2230-
String::new()
2211+
if candidates.len() < 5 {
2212+
let spans: Vec<_> =
2213+
candidates.iter().map(|(_, def_id)| self.tcx.def_span(def_id)).collect();
2214+
let mut span: MultiSpan = spans.into();
2215+
for (c, def_id) in &candidates {
2216+
let msg = if all_traits_equal {
2217+
format!("`{}`", self.tcx.short_string(c.self_ty(), err.long_ty_path()))
2218+
} else {
2219+
format!(
2220+
"`{}` implements `{}`",
2221+
self.tcx.short_string(c.self_ty(), err.long_ty_path()),
2222+
self.tcx.short_string(c.print_only_trait_path(), err.long_ty_path()),
2223+
)
2224+
};
2225+
span.push_span_label(self.tcx.def_span(def_id), msg);
22312226
}
2232-
));
2227+
err.span_help(
2228+
span,
2229+
format!(
2230+
"the following {other}types implement trait `{}`",
2231+
trait_ref.print_trait_sugared(),
2232+
),
2233+
);
2234+
} else {
2235+
let candidate_names: Vec<String> = candidates
2236+
.iter()
2237+
.map(|(c, _)| {
2238+
if all_traits_equal {
2239+
format!(
2240+
"\n {}",
2241+
self.tcx.short_string(c.self_ty(), err.long_ty_path())
2242+
)
2243+
} else {
2244+
format!(
2245+
"\n `{}` implements `{}`",
2246+
self.tcx.short_string(c.self_ty(), err.long_ty_path()),
2247+
self.tcx
2248+
.short_string(c.print_only_trait_path(), err.long_ty_path()),
2249+
)
2250+
}
2251+
})
2252+
.collect();
2253+
err.help(format!(
2254+
"the following {other}types implement trait `{}`:{}{}",
2255+
trait_ref.print_trait_sugared(),
2256+
candidate_names[..end].join(""),
2257+
if candidates.len() > 9 && !self.tcx.sess.opts.verbose {
2258+
format!("\nand {} others", candidates.len() - 8)
2259+
} else {
2260+
String::new()
2261+
}
2262+
));
2263+
}
22332264
true
22342265
};
22352266

@@ -2279,7 +2310,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
22792310
.collect();
22802311
impl_candidates.sort_by_key(|cand| (cand.similarity, cand.trait_ref.to_string()));
22812312
let mut impl_candidates: Vec<_> =
2282-
impl_candidates.into_iter().map(|cand| cand.trait_ref).collect();
2313+
impl_candidates.into_iter().map(|cand| (cand.trait_ref, cand.impl_def_id)).collect();
22832314
impl_candidates.dedup();
22842315

22852316
report(impl_candidates, err)

tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@ help: the trait `VisitorResult` is not implemented for `NotAValidResultType`
99
|
1010
LL | struct NotAValidResultType;
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
12-
= help: the following other types implement trait `VisitorResult`:
13-
()
14-
ControlFlow<T>
12+
help: the following other types implement trait `VisitorResult`
13+
--> /rustc-dev/xyz/compiler/rustc_ast_ir/src/visit.rs:LL:COL
14+
|
15+
= note: `()`
16+
::: /rustc-dev/xyz/compiler/rustc_ast_ir/src/visit.rs:LL:COL
17+
|
18+
= note: `ControlFlow<T>`
1519
note: required by a bound in `rustc_ast::visit::Visitor::Result`
1620
--> /rustc-dev/xyz/compiler/rustc_ast/src/visit.rs:LL:COL
1721
= note: this error originates in the macro `common_visitor_and_walkers` (in Nightly builds, run with -Z macro-backtrace for more info)

tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,14 @@ help: the trait `VisitorResult` is not implemented for `NotAValidResultType`
99
|
1010
LL | struct NotAValidResultType;
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
12-
= help: the following other types implement trait `VisitorResult`:
13-
()
14-
ControlFlow<T>
12+
help: the following other types implement trait `VisitorResult`
13+
--> $COMPILER_DIR_REAL/rustc_ast_ir/src/visit.rs:LL:COL
14+
|
15+
LL | impl VisitorResult for () {
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ `()`
17+
...
18+
LL | impl<T> VisitorResult for ControlFlow<T> {
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ControlFlow<T>`
1520
note: required by a bound in `rustc_ast::visit::Visitor::Result`
1621
--> $COMPILER_DIR_REAL/rustc_ast/src/visit.rs:LL:COL
1722
|

tests/ui/allocator/not-an-allocator.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//@ revisions: u w
2+
//@[u] only-unix
3+
//@[w] only-windows
14
#[global_allocator]
25
static A: usize = 0;
36
//~^ ERROR E0277

tests/ui/allocator/not-an-allocator.stderr renamed to tests/ui/allocator/not-an-allocator.u.stderr

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,48 @@
11
error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
2-
--> $DIR/not-an-allocator.rs:2:11
2+
--> $DIR/not-an-allocator.rs:5:11
33
|
44
LL | #[global_allocator]
55
| ------------------- in this attribute macro expansion
66
LL | static A: usize = 0;
77
| ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
88
|
9-
= help: the trait `GlobalAlloc` is implemented for `System`
9+
help: the trait `GlobalAlloc` is implemented for `System`
10+
--> $SRC_DIR/std/src/sys/alloc/unix.rs:LL:COL
1011

1112
error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
12-
--> $DIR/not-an-allocator.rs:2:11
13+
--> $DIR/not-an-allocator.rs:5:11
1314
|
1415
LL | #[global_allocator]
1516
| ------------------- in this attribute macro expansion
1617
LL | static A: usize = 0;
1718
| ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
1819
|
19-
= help: the trait `GlobalAlloc` is implemented for `System`
20+
help: the trait `GlobalAlloc` is implemented for `System`
21+
--> $SRC_DIR/std/src/sys/alloc/unix.rs:LL:COL
2022
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
2123

2224
error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
23-
--> $DIR/not-an-allocator.rs:2:11
25+
--> $DIR/not-an-allocator.rs:5:11
2426
|
2527
LL | #[global_allocator]
2628
| ------------------- in this attribute macro expansion
2729
LL | static A: usize = 0;
2830
| ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
2931
|
30-
= help: the trait `GlobalAlloc` is implemented for `System`
32+
help: the trait `GlobalAlloc` is implemented for `System`
33+
--> $SRC_DIR/std/src/sys/alloc/unix.rs:LL:COL
3134
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
3235

3336
error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
34-
--> $DIR/not-an-allocator.rs:2:11
37+
--> $DIR/not-an-allocator.rs:5:11
3538
|
3639
LL | #[global_allocator]
3740
| ------------------- in this attribute macro expansion
3841
LL | static A: usize = 0;
3942
| ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
4043
|
41-
= help: the trait `GlobalAlloc` is implemented for `System`
44+
help: the trait `GlobalAlloc` is implemented for `System`
45+
--> $SRC_DIR/std/src/sys/alloc/unix.rs:LL:COL
4246
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
4347

4448
error: aborting due to 4 previous errors
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
2+
--> $DIR/not-an-allocator.rs:5:11
3+
|
4+
LL | #[global_allocator]
5+
| ------------------- in this attribute macro expansion
6+
LL | static A: usize = 0;
7+
| ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
8+
|
9+
help: the trait `GlobalAlloc` is implemented for `System`
10+
--> $SRC_DIR/std/src/sys/alloc/windows.rs:LL:COL
11+
12+
error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
13+
--> $DIR/not-an-allocator.rs:5:11
14+
|
15+
LL | #[global_allocator]
16+
| ------------------- in this attribute macro expansion
17+
LL | static A: usize = 0;
18+
| ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
19+
|
20+
help: the trait `GlobalAlloc` is implemented for `System`
21+
--> $SRC_DIR/std/src/sys/alloc/windows.rs:LL:COL
22+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
23+
24+
error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
25+
--> $DIR/not-an-allocator.rs:5:11
26+
|
27+
LL | #[global_allocator]
28+
| ------------------- in this attribute macro expansion
29+
LL | static A: usize = 0;
30+
| ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
31+
|
32+
help: the trait `GlobalAlloc` is implemented for `System`
33+
--> $SRC_DIR/std/src/sys/alloc/windows.rs:LL:COL
34+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
35+
36+
error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
37+
--> $DIR/not-an-allocator.rs:5:11
38+
|
39+
LL | #[global_allocator]
40+
| ------------------- in this attribute macro expansion
41+
LL | static A: usize = 0;
42+
| ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
43+
|
44+
help: the trait `GlobalAlloc` is implemented for `System`
45+
--> $SRC_DIR/std/src/sys/alloc/windows.rs:LL:COL
46+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
47+
48+
error: aborting due to 4 previous errors
49+
50+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)