Skip to content

Commit 9c8f2b9

Browse files
committed
Use root obligation on E0277 for some cases
When encountering trait bound errors that satisfy some heuristics that tell us that the relevant trait for the user comes from the root obligation and not the current obligation, we use the root predicate for the main message. This allows to talk about "X doesn't implement Pattern<'_>" over the most specific case that just happened to fail, like "char doesn't implement Fn(&mut char)" in `tests/ui/traits/suggest-dereferences/root-obligation.rs` The heuristics are: - the type of the leaf predicate is (roughly) the same as the type from the root predicate, as a proxy for "we care about the root" - the leaf trait and the root trait are different, so as to avoid talking about `&mut T: Trait` and instead remain talking about `T: Trait` instead - the root trait is not `Unsize`, as to avoid talking about it in `tests/ui/coercion/coerce-issue-49593-box-never.rs`. ``` error[E0277]: the trait bound `&char: Pattern<'_>` is not satisfied --> $DIR/root-obligation.rs:6:38 | LL | .filter(|c| "aeiou".contains(c)) | -------- ^ the trait `Fn<(char,)>` is not implemented for `&char`, which is required by `&char: Pattern<'_>` | | | required by a bound introduced by this call | = note: required for `&char` to implement `FnOnce<(char,)>` = note: required for `&char` to implement `Pattern<'_>` note: required by a bound in `core::str::<impl str>::contains` --> $SRC_DIR/core/src/str/mod.rs:LL:COL help: consider dereferencing here | LL | .filter(|c| "aeiou".contains(*c)) | + ``` Fix #79359, fix #119983, fix #118779, cc #118415 (the suggestion needs to change).
1 parent c475e23 commit 9c8f2b9

38 files changed

+155
-78
lines changed

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

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -409,9 +409,43 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
409409
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
410410
let trait_predicate = bound_predicate.rebind(trait_predicate);
411411
let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
412-
let trait_ref = trait_predicate.to_poly_trait_ref();
413412

414-
if let Some(guar) = self.emit_specialized_closure_kind_error(&obligation, trait_ref) {
413+
// Let's use the root obligation as the main message, when we care about the
414+
// most general case ("X doesn't implement Pattern<'_>") over the case that
415+
// happened to fail ("char doesn't implement Fn(&mut char)").
416+
//
417+
// We rely on a few heuristics to identify cases where this root
418+
// obligation is more important than the leaf obligation:
419+
let (main_trait_predicate, o) = if let ty::PredicateKind::Clause(
420+
ty::ClauseKind::Trait(root_pred)
421+
) = root_obligation.predicate.kind().skip_binder()
422+
// The type of the leaf predicate is (roughly) the same as the type
423+
// from the root predicate, as a proxy for "we care about the root"
424+
&& trait_predicate.self_ty().skip_binder()
425+
== root_pred.self_ty().peel_refs()
426+
// The leaf trait and the root trait are different, so as to avoid
427+
// talking about `&mut T: Trait` and instead remain talking about
428+
// `T: Trait` instead
429+
&& trait_predicate.def_id() != root_pred.def_id()
430+
// The root trait is not `Unsize`, as to avoid talking about it in
431+
// `tests/ui/coercion/coerce-issue-49593-box-never.rs`.
432+
&& Some(root_pred.def_id()) != self.tcx.lang_items().unsize_trait()
433+
{
434+
(
435+
self.resolve_vars_if_possible(
436+
root_obligation.predicate.kind().rebind(root_pred),
437+
),
438+
root_obligation,
439+
)
440+
} else {
441+
(trait_predicate, &obligation)
442+
};
443+
let trait_ref = main_trait_predicate.to_poly_trait_ref();
444+
445+
if let Some(guar) = self.emit_specialized_closure_kind_error(
446+
&obligation,
447+
trait_ref,
448+
) {
415449
return guar;
416450
}
417451

@@ -450,7 +484,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
450484
notes,
451485
parent_label,
452486
append_const_msg,
453-
} = self.on_unimplemented_note(trait_ref, &obligation);
487+
} = self.on_unimplemented_note(trait_ref, o);
454488
let have_alt_message = message.is_some() || label.is_some();
455489
let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id());
456490
let is_unsize =
@@ -473,7 +507,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
473507
};
474508

475509
let err_msg = self.get_standard_error_message(
476-
&trait_predicate,
510+
&main_trait_predicate,
477511
message,
478512
predicate_is_const,
479513
append_const_msg,

library/core/src/future/into_future.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ use crate::future::Future;
100100
/// ```
101101
#[stable(feature = "into_future", since = "1.64.0")]
102102
#[rustc_diagnostic_item = "IntoFuture"]
103+
#[diagnostic::on_unimplemented(
104+
label = "`{Self}` is not a future",
105+
message = "`{Self}` is not a future",
106+
note = "{Self} must be a future or must implement `IntoFuture` to be awaited"
107+
)]
103108
pub trait IntoFuture {
104109
/// The output that the future will produce on completion.
105110
#[stable(feature = "into_future", since = "1.64.0")]

library/core/src/iter/traits/collect.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,49 @@ pub trait FromIterator<A>: Sized {
236236
/// ```
237237
#[rustc_diagnostic_item = "IntoIterator"]
238238
#[rustc_skip_array_during_method_dispatch]
239+
#[rustc_on_unimplemented(
240+
on(
241+
_Self = "core::ops::range::RangeTo<Idx>",
242+
label = "if you meant to iterate until a value, add a starting value",
243+
note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \
244+
bounded `Range`: `0..end`"
245+
),
246+
on(
247+
_Self = "core::ops::range::RangeToInclusive<Idx>",
248+
label = "if you meant to iterate until a value (including it), add a starting value",
249+
note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \
250+
to have a bounded `RangeInclusive`: `0..=end`"
251+
),
252+
on(
253+
_Self = "[]",
254+
label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
255+
),
256+
on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"),
257+
on(
258+
_Self = "alloc::vec::Vec<T, A>",
259+
label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
260+
),
261+
on(
262+
_Self = "&str",
263+
label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
264+
),
265+
on(
266+
_Self = "alloc::string::String",
267+
label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
268+
),
269+
on(
270+
_Self = "{integral}",
271+
note = "if you want to iterate between `start` until a value `end`, use the exclusive range \
272+
syntax `start..end` or the inclusive range syntax `start..=end`"
273+
),
274+
on(
275+
_Self = "{float}",
276+
note = "if you want to iterate between `start` until a value `end`, use the exclusive range \
277+
syntax `start..end` or the inclusive range syntax `start..=end`"
278+
),
279+
label = "`{Self}` is not an iterator",
280+
message = "`{Self}` is not an iterator"
281+
)]
239282
#[stable(feature = "rust1", since = "1.0.0")]
240283
pub trait IntoIterator {
241284
/// The type of the elements being iterated over.

tests/ui/associated-types/substs-ppaux.normal.stderr

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,12 @@ help: use parentheses to call this function
7070
LL | let x: () = foo::<'static>();
7171
| ++
7272

73-
error[E0277]: the size for values of type `str` cannot be known at compilation time
73+
error[E0277]: the trait bound `str: Foo<'_, '_, u8>` is not satisfied
7474
--> $DIR/substs-ppaux.rs:49:6
7575
|
7676
LL | <str as Foo<u8>>::bar;
77-
| ^^^ doesn't have a size known at compile-time
77+
| ^^^ the trait `Sized` is not implemented for `str`, which is required by `str: Foo<'_, '_, u8>`
7878
|
79-
= help: the trait `Sized` is not implemented for `str`, which is required by `str: Foo<'_, '_, u8>`
8079
note: required for `str` to implement `Foo<'_, '_, u8>`
8180
--> $DIR/substs-ppaux.rs:11:17
8281
|

tests/ui/associated-types/substs-ppaux.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,6 @@ fn foo<'z>() where &'z (): Sized {
4747
//[normal]~| found fn item `fn() {foo::<'static>}`
4848

4949
<str as Foo<u8>>::bar;
50-
//[verbose]~^ ERROR the size for values of type
51-
//[normal]~^^ ERROR the size for values of type
50+
//[verbose]~^ ERROR the trait bound `str: Foo<'?0, '?1, u8>` is not satisfied
51+
//[normal]~^^ ERROR the trait bound `str: Foo<'_, '_, u8>` is not satisfied
5252
}

tests/ui/associated-types/substs-ppaux.verbose.stderr

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,12 @@ help: use parentheses to call this function
7070
LL | let x: () = foo::<'static>();
7171
| ++
7272

73-
error[E0277]: the size for values of type `str` cannot be known at compilation time
73+
error[E0277]: the trait bound `str: Foo<'?0, '?1, u8>` is not satisfied
7474
--> $DIR/substs-ppaux.rs:49:6
7575
|
7676
LL | <str as Foo<u8>>::bar;
77-
| ^^^ doesn't have a size known at compile-time
77+
| ^^^ the trait `Sized` is not implemented for `str`, which is required by `str: Foo<'?0, '?1, u8>`
7878
|
79-
= help: the trait `Sized` is not implemented for `str`, which is required by `str: Foo<'?0, '?1, u8>`
8079
note: required for `str` to implement `Foo<'?0, '?1, u8>`
8180
--> $DIR/substs-ppaux.rs:11:17
8281
|

tests/ui/auto-traits/typeck-default-trait-impl-precedence.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ impl Signed for i32 { }
1717
fn main() {
1818
is_defaulted::<&'static i32>();
1919
is_defaulted::<&'static u32>();
20-
//~^ ERROR `u32: Signed` is not satisfied
20+
//~^ ERROR the trait bound `&'static u32: Defaulted` is not satisfied
2121
}

tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0277]: the trait bound `u32: Signed` is not satisfied
1+
error[E0277]: the trait bound `&'static u32: Defaulted` is not satisfied
22
--> $DIR/typeck-default-trait-impl-precedence.rs:19:20
33
|
44
LL | is_defaulted::<&'static u32>();
5-
| ^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32`, which is required by `&'static u32: Defaulted`
5+
| ^^^^^^^^^^^^ the trait `Signed` is not implemented for `&'static u32`, which is required by `&'static u32: Defaulted`
66
|
77
note: required for `&'static u32` to implement `Defaulted`
88
--> $DIR/typeck-default-trait-impl-precedence.rs:10:19

tests/ui/for/issue-20605.current.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0277]: the size for values of type `dyn Iterator<Item = &'a mut u8>` cannot be known at compilation time
1+
error[E0277]: `dyn Iterator<Item = &'a mut u8>` is not an iterator
22
--> $DIR/issue-20605.rs:5:17
33
|
44
LL | for item in *things { *item = 0 }

tests/ui/for/issue-20605.next.stderr

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
error[E0277]: the trait bound `dyn Iterator<Item = &'a mut u8>: IntoIterator` is not satisfied
1+
error[E0277]: `dyn Iterator<Item = &'a mut u8>` is not an iterator
22
--> $DIR/issue-20605.rs:5:17
33
|
44
LL | for item in *things { *item = 0 }
5-
| ^^^^^^^ the trait `IntoIterator` is not implemented for `dyn Iterator<Item = &'a mut u8>`
5+
| ^^^^^^^ `dyn Iterator<Item = &'a mut u8>` is not an iterator
6+
|
7+
= help: the trait `IntoIterator` is not implemented for `dyn Iterator<Item = &'a mut u8>`
68

79
error: the type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
810
--> $DIR/issue-20605.rs:5:17

0 commit comments

Comments
 (0)