Skip to content

Commit bd3ac03

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 fca2e94 + 32aa599 commit bd3ac03

File tree

159 files changed

+1795
-656
lines changed

Some content is hidden

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

159 files changed

+1795
-656
lines changed

compiler/rustc_errors/src/emitter.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,16 +1523,17 @@ impl HumanEmitter {
15231523
label_width += 2;
15241524
}
15251525
let mut line = 0;
1526+
let mut pad = false;
15261527
for (text, style) in msgs.iter() {
15271528
let text =
15281529
self.translator.translate_message(text, args).map_err(Report::new).unwrap();
15291530
// Account for newlines to align output to its label.
1530-
for text in normalize_whitespace(&text).lines() {
1531+
for text in normalize_whitespace(&text).split('\n') {
15311532
buffer.append(
15321533
line,
15331534
&format!(
15341535
"{}{}",
1535-
if line == 0 { String::new() } else { " ".repeat(label_width) },
1536+
if pad { " ".repeat(label_width) } else { String::new() },
15361537
text
15371538
),
15381539
match style {
@@ -1541,7 +1542,9 @@ impl HumanEmitter {
15411542
},
15421543
);
15431544
line += 1;
1545+
pad = true;
15441546
}
1547+
pad = false;
15451548
// We add lines above, but if the last line has no explicit newline (which would
15461549
// yield an empty line), then we revert one line up to continue with the next
15471550
// 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: 79 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// ignore-tidy-filelength
12
use core::ops::ControlFlow;
23
use std::borrow::Cow;
34
use std::path::PathBuf;
@@ -1906,13 +1907,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
19061907
// ignore `do_not_recommend` items
19071908
.filter(|def_id| !self.tcx.do_not_recommend_impl(*def_id))
19081909
// Ignore automatically derived impls and `!Trait` impls.
1909-
.map(|def_id| self.tcx.impl_trait_header(def_id))
1910-
.filter_map(|header| {
1911-
(header.polarity != ty::ImplPolarity::Negative
1910+
.map(|def_id| (self.tcx.impl_trait_header(def_id), def_id))
1911+
.filter_map(|(header, def_id)| {
1912+
(header.polarity == ty::ImplPolarity::Positive
19121913
|| self.tcx.is_automatically_derived(def_id))
1913-
.then(|| header.trait_ref.instantiate_identity())
1914+
.then(|| (header.trait_ref.instantiate_identity(), def_id))
19141915
})
1915-
.filter(|trait_ref| {
1916+
.filter(|(trait_ref, _)| {
19161917
let self_ty = trait_ref.self_ty();
19171918
// Avoid mentioning type parameters.
19181919
if let ty::Param(_) = self_ty.kind() {
@@ -1944,7 +1945,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
19441945
})
19451946
.collect();
19461947

1947-
impl_candidates.sort_by_key(|tr| tr.to_string());
1948+
impl_candidates.sort_by_key(|(tr, _)| tr.to_string());
19481949
impl_candidates.dedup();
19491950
impl_candidates
19501951
};
@@ -1972,7 +1973,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
19721973
let candidates = if impl_candidates.is_empty() {
19731974
alternative_candidates(trait_def_id)
19741975
} else {
1975-
impl_candidates.into_iter().map(|cand| cand.trait_ref).collect()
1976+
impl_candidates.into_iter().map(|cand| (cand.trait_ref, cand.impl_def_id)).collect()
19761977
};
19771978
let mut span: MultiSpan = self.tcx.def_span(trait_def_id).into();
19781979
span.push_span_label(self.tcx.def_span(trait_def_id), "this is the required trait");
@@ -2004,7 +2005,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
20042005
self.tcx.def_span(found_type),
20052006
"this type doesn't implement the required trait",
20062007
);
2007-
for trait_ref in candidates {
2008+
for (trait_ref, _) in candidates {
20082009
if let ty::Adt(def, _) = trait_ref.self_ty().peel_refs().kind()
20092010
&& let candidate_def_id = def.did()
20102011
&& let Some(name) = self.tcx.opt_item_name(candidate_def_id)
@@ -2191,7 +2192,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
21912192
msg.extend(types.1.0);
21922193
msg.push(StringPart::normal("`"));
21932194
}
2194-
err.highlighted_help(msg);
2195+
err.highlighted_span_help(self.tcx.def_span(single.impl_def_id), msg);
21952196

21962197
if let [TypeError::Sorts(exp_found)] = &terrs[..] {
21972198
let exp_found = self.resolve_vars_if_possible(*exp_found);
@@ -2217,12 +2218,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
22172218
}
22182219

22192220
let other = if other { "other " } else { "" };
2220-
let report = |mut candidates: Vec<TraitRef<'tcx>>, err: &mut Diag<'_>| {
2221-
candidates.retain(|tr| !tr.references_error());
2221+
let report = |mut candidates: Vec<(TraitRef<'tcx>, DefId)>, err: &mut Diag<'_>| {
2222+
candidates.retain(|(tr, _)| !tr.references_error());
22222223
if candidates.is_empty() {
22232224
return false;
22242225
}
2225-
if let &[cand] = &candidates[..] {
2226+
if let &[(cand, def_id)] = &candidates[..] {
22262227
if self.tcx.is_diagnostic_item(sym::FromResidual, cand.def_id)
22272228
&& !self.tcx.features().enabled(sym::try_trait_v2)
22282229
{
@@ -2238,56 +2239,87 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
22382239
};
22392240
let trait_ = self.tcx.short_string(cand.print_trait_sugared(), err.long_ty_path());
22402241
let self_ty = self.tcx.short_string(cand.self_ty(), err.long_ty_path());
2241-
err.highlighted_help(vec![
2242-
StringPart::normal(format!("the trait `{trait_}` ",)),
2243-
StringPart::highlighted("is"),
2244-
StringPart::normal(desc),
2245-
StringPart::highlighted(self_ty),
2246-
StringPart::normal("`"),
2247-
StringPart::normal(mention_castable),
2248-
]);
2242+
err.highlighted_span_help(
2243+
self.tcx.def_span(def_id),
2244+
vec![
2245+
StringPart::normal(format!("the trait `{trait_}` ",)),
2246+
StringPart::highlighted("is"),
2247+
StringPart::normal(desc),
2248+
StringPart::highlighted(self_ty),
2249+
StringPart::normal("`"),
2250+
StringPart::normal(mention_castable),
2251+
],
2252+
);
22492253
return true;
22502254
}
2251-
let trait_ref = TraitRef::identity(self.tcx, candidates[0].def_id);
2255+
let trait_ref = TraitRef::identity(self.tcx, candidates[0].0.def_id);
22522256
// Check if the trait is the same in all cases. If so, we'll only show the type.
22532257
let mut traits: Vec<_> =
2254-
candidates.iter().map(|c| c.print_only_trait_path().to_string()).collect();
2258+
candidates.iter().map(|(c, _)| c.print_only_trait_path().to_string()).collect();
22552259
traits.sort();
22562260
traits.dedup();
22572261
// FIXME: this could use a better heuristic, like just checking
22582262
// that args[1..] is the same.
22592263
let all_traits_equal = traits.len() == 1;
22602264

2261-
let candidates: Vec<String> = candidates
2262-
.into_iter()
2263-
.map(|c| {
2264-
if all_traits_equal {
2265-
format!("\n {}", self.tcx.short_string(c.self_ty(), err.long_ty_path()))
2266-
} else {
2267-
format!(
2268-
"\n `{}` implements `{}`",
2269-
self.tcx.short_string(c.self_ty(), err.long_ty_path()),
2270-
self.tcx.short_string(c.print_only_trait_path(), err.long_ty_path()),
2271-
)
2272-
}
2273-
})
2274-
.collect();
2275-
22762265
let end = if candidates.len() <= 9 || self.tcx.sess.opts.verbose {
22772266
candidates.len()
22782267
} else {
22792268
8
22802269
};
2281-
err.help(format!(
2282-
"the following {other}types implement trait `{}`:{}{}",
2283-
trait_ref.print_trait_sugared(),
2284-
candidates[..end].join(""),
2285-
if candidates.len() > 9 && !self.tcx.sess.opts.verbose {
2286-
format!("\nand {} others", candidates.len() - 8)
2287-
} else {
2288-
String::new()
2270+
if candidates.len() < 5 {
2271+
let spans: Vec<_> =
2272+
candidates.iter().map(|(_, def_id)| self.tcx.def_span(def_id)).collect();
2273+
let mut span: MultiSpan = spans.into();
2274+
for (c, def_id) in &candidates {
2275+
let msg = if all_traits_equal {
2276+
format!("`{}`", self.tcx.short_string(c.self_ty(), err.long_ty_path()))
2277+
} else {
2278+
format!(
2279+
"`{}` implements `{}`",
2280+
self.tcx.short_string(c.self_ty(), err.long_ty_path()),
2281+
self.tcx.short_string(c.print_only_trait_path(), err.long_ty_path()),
2282+
)
2283+
};
2284+
span.push_span_label(self.tcx.def_span(def_id), msg);
22892285
}
2290-
));
2286+
err.span_help(
2287+
span,
2288+
format!(
2289+
"the following {other}types implement trait `{}`",
2290+
trait_ref.print_trait_sugared(),
2291+
),
2292+
);
2293+
} else {
2294+
let candidate_names: Vec<String> = candidates
2295+
.iter()
2296+
.map(|(c, _)| {
2297+
if all_traits_equal {
2298+
format!(
2299+
"\n {}",
2300+
self.tcx.short_string(c.self_ty(), err.long_ty_path())
2301+
)
2302+
} else {
2303+
format!(
2304+
"\n `{}` implements `{}`",
2305+
self.tcx.short_string(c.self_ty(), err.long_ty_path()),
2306+
self.tcx
2307+
.short_string(c.print_only_trait_path(), err.long_ty_path()),
2308+
)
2309+
}
2310+
})
2311+
.collect();
2312+
err.help(format!(
2313+
"the following {other}types implement trait `{}`:{}{}",
2314+
trait_ref.print_trait_sugared(),
2315+
candidate_names[..end].join(""),
2316+
if candidates.len() > 9 && !self.tcx.sess.opts.verbose {
2317+
format!("\nand {} others", candidates.len() - 8)
2318+
} else {
2319+
String::new()
2320+
}
2321+
));
2322+
}
22912323
true
22922324
};
22932325

@@ -2349,7 +2381,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
23492381
(cand.similarity, len, cand.trait_ref.to_string())
23502382
});
23512383
let mut impl_candidates: Vec<_> =
2352-
impl_candidates.into_iter().map(|cand| cand.trait_ref).collect();
2384+
impl_candidates.into_iter().map(|cand| (cand.trait_ref, cand.impl_def_id)).collect();
23532385
impl_candidates.dedup();
23542386

23552387
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)