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).
This commit is contained in:
parent
26907374b9
commit
f0c93117ed
49 changed files with 166 additions and 120 deletions
|
@ -416,9 +416,51 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
|
||||
let trait_predicate = bound_predicate.rebind(trait_predicate);
|
||||
let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
|
||||
let trait_ref = trait_predicate.to_poly_trait_ref();
|
||||
|
||||
if let Some(guar) = self.emit_specialized_closure_kind_error(&obligation, trait_ref) {
|
||||
// Let's use the root obligation as the main message, when we care about the
|
||||
// most general case ("X doesn't implement Pattern<'_>") over the case that
|
||||
// happened to fail ("char doesn't implement Fn(&mut char)").
|
||||
//
|
||||
// We rely on a few heuristics to identify cases where this root
|
||||
// obligation is more important than the leaf obligation:
|
||||
let (main_trait_predicate, o) = if let ty::PredicateKind::Clause(
|
||||
ty::ClauseKind::Trait(root_pred)
|
||||
) = root_obligation.predicate.kind().skip_binder()
|
||||
// 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"
|
||||
// FIXME: this doesn't account for trivial derefs, but works as a first
|
||||
// approximation.
|
||||
&& (
|
||||
// `T: Trait` && `&&T: OtherTrait`, we want `OtherTrait`
|
||||
trait_predicate.self_ty().skip_binder()
|
||||
== root_pred.self_ty().peel_refs()
|
||||
// `&str: Iterator` && `&str: IntoIterator`, we want `IntoIterator`
|
||||
|| trait_predicate.self_ty().skip_binder()
|
||||
== root_pred.self_ty()
|
||||
)
|
||||
// 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
|
||||
&& trait_predicate.def_id() != root_pred.def_id()
|
||||
// The root trait is not `Unsize`, as to avoid talking about it in
|
||||
// `tests/ui/coercion/coerce-issue-49593-box-never.rs`.
|
||||
&& Some(root_pred.def_id()) != self.tcx.lang_items().unsize_trait()
|
||||
{
|
||||
(
|
||||
self.resolve_vars_if_possible(
|
||||
root_obligation.predicate.kind().rebind(root_pred),
|
||||
),
|
||||
root_obligation,
|
||||
)
|
||||
} else {
|
||||
(trait_predicate, &obligation)
|
||||
};
|
||||
let trait_ref = main_trait_predicate.to_poly_trait_ref();
|
||||
|
||||
if let Some(guar) = self.emit_specialized_closure_kind_error(
|
||||
&obligation,
|
||||
trait_ref,
|
||||
) {
|
||||
return guar;
|
||||
}
|
||||
|
||||
|
@ -459,8 +501,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
notes,
|
||||
parent_label,
|
||||
append_const_msg,
|
||||
} = self.on_unimplemented_note(trait_ref, &obligation, &mut long_ty_file);
|
||||
|
||||
} = self.on_unimplemented_note(trait_ref, o, &mut long_ty_file);
|
||||
let have_alt_message = message.is_some() || label.is_some();
|
||||
let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id());
|
||||
let is_unsize =
|
||||
|
@ -483,7 +524,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
};
|
||||
|
||||
let err_msg = self.get_standard_error_message(
|
||||
&trait_predicate,
|
||||
&main_trait_predicate,
|
||||
message,
|
||||
predicate_is_const,
|
||||
append_const_msg,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue