Rollup merge of #126142 - compiler-errors:trait-ref-split, r=jackh726
Harmonize using root or leaf obligation in trait error reporting When #121826 changed the error reporting to use root obligation and not the leafmost obligation, it didn't actually make sure that all the other diagnostics helper functions used the right obligation. Specifically, when reporting similar impl candidates we are looking for impls of the root obligation, but trying to match them against the trait ref of the leaf obligation. This does a few other miscellaneous changes. There's a lot more clean-up that could be done here, but working with this code is really grief-inducing due to how messy it has become over the years. Someone really needs to show it love. 😓 r? ``@estebank`` Fixes #126129
This commit is contained in:
commit
25c55c51cb
@ -546,7 +546,7 @@ fn suggest_constraint(
|
||||
for pred in hir_generics.bounds_for_param(def_id) {
|
||||
if self.constrain_generic_bound_associated_type_structured_suggestion(
|
||||
diag,
|
||||
&trait_ref,
|
||||
trait_ref,
|
||||
pred.bounds,
|
||||
assoc,
|
||||
assoc_args,
|
||||
@ -715,7 +715,7 @@ fn suggest_constraining_opaque_associated_type(
|
||||
|
||||
self.constrain_generic_bound_associated_type_structured_suggestion(
|
||||
diag,
|
||||
&trait_ref,
|
||||
trait_ref,
|
||||
opaque_hir_ty.bounds,
|
||||
assoc,
|
||||
assoc_args,
|
||||
@ -869,7 +869,7 @@ trait defining them",
|
||||
fn constrain_generic_bound_associated_type_structured_suggestion(
|
||||
&self,
|
||||
diag: &mut Diag<'_>,
|
||||
trait_ref: &ty::TraitRef<'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
bounds: hir::GenericBounds<'_>,
|
||||
assoc: ty::AssocItem,
|
||||
assoc_args: &[ty::GenericArg<'tcx>],
|
||||
|
@ -285,8 +285,7 @@ fn elaborate(&mut self, elaboratable: &O) {
|
||||
let obligations =
|
||||
predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| {
|
||||
elaboratable.child_with_derived_cause(
|
||||
clause
|
||||
.instantiate_supertrait(tcx, &bound_clause.rebind(data.trait_ref)),
|
||||
clause.instantiate_supertrait(tcx, bound_clause.rebind(data.trait_ref)),
|
||||
span,
|
||||
bound_clause.rebind(data),
|
||||
index,
|
||||
|
@ -37,7 +37,7 @@ fn elaborate(&mut self, trait_ref: PolyTraitRef<'tcx>) {
|
||||
let super_predicates =
|
||||
self.tcx.super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map(
|
||||
|&(pred, _)| {
|
||||
let clause = pred.instantiate_supertrait(self.tcx, &trait_ref);
|
||||
let clause = pred.instantiate_supertrait(self.tcx, trait_ref);
|
||||
self.visited.insert(clause).then_some(clause)
|
||||
},
|
||||
);
|
||||
|
@ -313,7 +313,7 @@ impl<'tcx> Clause<'tcx> {
|
||||
pub fn instantiate_supertrait(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: &ty::PolyTraitRef<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> Clause<'tcx> {
|
||||
// The interaction between HRTB and supertraits is not entirely
|
||||
// obvious. Let me walk you (and myself) through an example.
|
||||
|
@ -3597,7 +3597,7 @@ fn suggest_floating_point_literal(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut Diag<'_>,
|
||||
trait_ref: &ty::PolyTraitRef<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) {
|
||||
let rhs_span = match obligation.cause.code() {
|
||||
ObligationCauseCode::BinOp { rhs_span: Some(span), rhs_is_lit, .. } if *rhs_is_lit => {
|
||||
@ -4592,7 +4592,7 @@ fn suggest_add_result_as_return_type(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut Diag<'_>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) {
|
||||
if ObligationCauseCode::QuestionMark != *obligation.cause.code().peel_derives() {
|
||||
return;
|
||||
@ -4602,10 +4602,9 @@ fn suggest_add_result_as_return_type(
|
||||
if let hir::Node::Item(item) = node
|
||||
&& let hir::ItemKind::Fn(sig, _, body_id) = item.kind
|
||||
&& let hir::FnRetTy::DefaultReturn(ret_span) = sig.decl.output
|
||||
&& self.tcx.is_diagnostic_item(sym::FromResidual, trait_ref.def_id())
|
||||
&& let ty::Tuple(l) = trait_ref.skip_binder().args.type_at(0).kind()
|
||||
&& l.len() == 0
|
||||
&& let ty::Adt(def, _) = trait_ref.skip_binder().args.type_at(1).kind()
|
||||
&& self.tcx.is_diagnostic_item(sym::FromResidual, trait_pred.def_id())
|
||||
&& trait_pred.skip_binder().trait_ref.args.type_at(0).is_unit()
|
||||
&& let ty::Adt(def, _) = trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
|
||||
&& self.tcx.is_diagnostic_item(sym::Result, def.did())
|
||||
{
|
||||
let body = self.tcx.hir().body(body_id);
|
||||
@ -4863,14 +4862,13 @@ fn visit_ty(&mut self, t: &'hir hir::Ty<'hir>) {
|
||||
pub(super) fn get_explanation_based_on_obligation<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_predicate: &ty::PolyTraitPredicate<'tcx>,
|
||||
trait_predicate: ty::PolyTraitPredicate<'tcx>,
|
||||
pre_message: String,
|
||||
) -> String {
|
||||
if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
|
||||
"consider using `()`, or a `Result`".to_owned()
|
||||
} else {
|
||||
let ty_desc = match trait_ref.skip_binder().self_ty().kind() {
|
||||
let ty_desc = match trait_predicate.self_ty().skip_binder().kind() {
|
||||
ty::FnDef(_, _) => Some("fn item"),
|
||||
ty::Closure(_, _) => Some("closure"),
|
||||
_ => None,
|
||||
@ -4895,7 +4893,7 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>(
|
||||
format!(
|
||||
"{pre_message}the trait `{}` is not implemented for{desc} `{}`{post}",
|
||||
trait_predicate.print_modifiers_and_trait_path(),
|
||||
tcx.short_ty_string(trait_ref.skip_binder().self_ty(), &mut None),
|
||||
tcx.short_ty_string(trait_predicate.self_ty().skip_binder(), &mut None),
|
||||
)
|
||||
} else {
|
||||
// "the trait bound `T: !Send` is not satisfied" reads better than "`!Send` is
|
||||
|
@ -412,8 +412,8 @@ fn report_selection_error(
|
||||
let bound_predicate = obligation.predicate.kind();
|
||||
match bound_predicate.skip_binder() {
|
||||
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 leaf_trait_predicate =
|
||||
self.resolve_vars_if_possible(bound_predicate.rebind(trait_predicate));
|
||||
|
||||
// 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
|
||||
@ -424,7 +424,7 @@ fn report_selection_error(
|
||||
let (main_trait_predicate, o) = if let ty::PredicateKind::Clause(
|
||||
ty::ClauseKind::Trait(root_pred)
|
||||
) = root_obligation.predicate.kind().skip_binder()
|
||||
&& !trait_predicate.self_ty().skip_binder().has_escaping_bound_vars()
|
||||
&& !leaf_trait_predicate.self_ty().skip_binder().has_escaping_bound_vars()
|
||||
&& !root_pred.self_ty().has_escaping_bound_vars()
|
||||
// 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"
|
||||
@ -434,20 +434,20 @@ fn report_selection_error(
|
||||
// `T: Trait` && `&&T: OtherTrait`, we want `OtherTrait`
|
||||
self.can_eq(
|
||||
obligation.param_env,
|
||||
trait_predicate.self_ty().skip_binder(),
|
||||
leaf_trait_predicate.self_ty().skip_binder(),
|
||||
root_pred.self_ty().peel_refs(),
|
||||
)
|
||||
// `&str: Iterator` && `&str: IntoIterator`, we want `IntoIterator`
|
||||
|| self.can_eq(
|
||||
obligation.param_env,
|
||||
trait_predicate.self_ty().skip_binder(),
|
||||
leaf_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()
|
||||
&& leaf_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()
|
||||
@ -459,13 +459,14 @@ fn report_selection_error(
|
||||
root_obligation,
|
||||
)
|
||||
} else {
|
||||
(trait_predicate, &obligation)
|
||||
(leaf_trait_predicate, &obligation)
|
||||
};
|
||||
let trait_ref = main_trait_predicate.to_poly_trait_ref();
|
||||
let main_trait_ref = main_trait_predicate.to_poly_trait_ref();
|
||||
let leaf_trait_ref = leaf_trait_predicate.to_poly_trait_ref();
|
||||
|
||||
if let Some(guar) = self.emit_specialized_closure_kind_error(
|
||||
&obligation,
|
||||
trait_ref,
|
||||
leaf_trait_ref,
|
||||
) {
|
||||
return guar;
|
||||
}
|
||||
@ -473,7 +474,7 @@ fn report_selection_error(
|
||||
// FIXME(effects)
|
||||
let predicate_is_const = false;
|
||||
|
||||
if let Err(guar) = trait_predicate.error_reported()
|
||||
if let Err(guar) = leaf_trait_predicate.error_reported()
|
||||
{
|
||||
return guar;
|
||||
}
|
||||
@ -507,16 +508,17 @@ fn report_selection_error(
|
||||
notes,
|
||||
parent_label,
|
||||
append_const_msg,
|
||||
} = self.on_unimplemented_note(trait_ref, o, &mut long_ty_file);
|
||||
} = self.on_unimplemented_note(main_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_try_conversion = self.is_try_conversion(span, main_trait_ref.def_id());
|
||||
let is_unsize =
|
||||
Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait();
|
||||
Some(leaf_trait_ref.def_id()) == self.tcx.lang_items().unsize_trait();
|
||||
let (message, notes, append_const_msg) = if is_try_conversion {
|
||||
(
|
||||
Some(format!(
|
||||
"`?` couldn't convert the error to `{}`",
|
||||
trait_ref.skip_binder().self_ty(),
|
||||
main_trait_ref.skip_binder().self_ty(),
|
||||
)),
|
||||
vec![
|
||||
"the question mark operation (`?`) implicitly performs a \
|
||||
@ -530,20 +532,20 @@ fn report_selection_error(
|
||||
};
|
||||
|
||||
let err_msg = self.get_standard_error_message(
|
||||
&main_trait_predicate,
|
||||
main_trait_predicate,
|
||||
message,
|
||||
predicate_is_const,
|
||||
append_const_msg,
|
||||
post_message,
|
||||
);
|
||||
|
||||
let (err_msg, safe_transmute_explanation) = if Some(trait_ref.def_id())
|
||||
let (err_msg, safe_transmute_explanation) = if Some(main_trait_ref.def_id())
|
||||
== self.tcx.lang_items().transmute_trait()
|
||||
{
|
||||
// Recompute the safe transmute reason and use that for the error reporting
|
||||
match self.get_safe_transmute_error_and_reason(
|
||||
obligation.clone(),
|
||||
trait_ref,
|
||||
main_trait_ref,
|
||||
span,
|
||||
) {
|
||||
GetSafeTransmuteErrorAndReason::Silent => {
|
||||
@ -571,7 +573,7 @@ fn report_selection_error(
|
||||
}
|
||||
let mut suggested = false;
|
||||
if is_try_conversion {
|
||||
suggested = self.try_conversion_context(&obligation, trait_ref.skip_binder(), &mut err);
|
||||
suggested = self.try_conversion_context(&obligation, main_trait_ref.skip_binder(), &mut err);
|
||||
}
|
||||
|
||||
if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
|
||||
@ -579,19 +581,19 @@ fn report_selection_error(
|
||||
ret_span,
|
||||
format!(
|
||||
"expected `{}` because of this",
|
||||
trait_ref.skip_binder().self_ty()
|
||||
main_trait_ref.skip_binder().self_ty()
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
|
||||
if Some(leaf_trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
|
||||
self.add_tuple_trait_message(
|
||||
obligation.cause.code().peel_derives(),
|
||||
&mut err,
|
||||
);
|
||||
}
|
||||
|
||||
if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait()
|
||||
if Some(leaf_trait_ref.def_id()) == tcx.lang_items().drop_trait()
|
||||
&& predicate_is_const
|
||||
{
|
||||
err.note("`~const Drop` was renamed to `~const Destruct`");
|
||||
@ -601,24 +603,25 @@ fn report_selection_error(
|
||||
let explanation = get_explanation_based_on_obligation(
|
||||
self.tcx,
|
||||
&obligation,
|
||||
trait_ref,
|
||||
&trait_predicate,
|
||||
leaf_trait_predicate,
|
||||
pre_message,
|
||||
);
|
||||
|
||||
self.check_for_binding_assigned_block_without_tail_expression(
|
||||
&obligation,
|
||||
&mut err,
|
||||
trait_predicate,
|
||||
leaf_trait_predicate,
|
||||
);
|
||||
self.suggest_add_result_as_return_type(&obligation,
|
||||
self.suggest_add_result_as_return_type(
|
||||
&obligation,
|
||||
&mut err,
|
||||
trait_ref);
|
||||
leaf_trait_predicate,
|
||||
);
|
||||
|
||||
if self.suggest_add_reference_to_arg(
|
||||
&obligation,
|
||||
&mut err,
|
||||
trait_predicate,
|
||||
leaf_trait_predicate,
|
||||
have_alt_message,
|
||||
) {
|
||||
self.note_obligation_cause(&mut err, &obligation);
|
||||
@ -630,7 +633,7 @@ fn report_selection_error(
|
||||
// If it has a custom `#[rustc_on_unimplemented]`
|
||||
// error message, let's display it as the label!
|
||||
err.span_label(span, s);
|
||||
if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
|
||||
if !matches!(leaf_trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
|
||||
// When the self type is a type param We don't need to "the trait
|
||||
// `std::marker::Sized` is not implemented for `T`" as we will point
|
||||
// at the type param with a label to suggest constraining it.
|
||||
@ -645,7 +648,7 @@ fn report_selection_error(
|
||||
if let ObligationCauseCode::Coercion { source, target } =
|
||||
*obligation.cause.code().peel_derives()
|
||||
{
|
||||
if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
|
||||
if Some(leaf_trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
|
||||
self.suggest_borrowing_for_object_cast(
|
||||
&mut err,
|
||||
root_obligation,
|
||||
@ -657,7 +660,7 @@ fn report_selection_error(
|
||||
|
||||
let UnsatisfiedConst(unsatisfied_const) = self
|
||||
.maybe_add_note_for_unsatisfied_const(
|
||||
&trait_predicate,
|
||||
leaf_trait_predicate,
|
||||
&mut err,
|
||||
span,
|
||||
);
|
||||
@ -674,15 +677,15 @@ fn report_selection_error(
|
||||
err.span_label(tcx.def_span(body), s);
|
||||
}
|
||||
|
||||
self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref);
|
||||
self.suggest_dereferencing_index(&obligation, &mut err, trait_predicate);
|
||||
suggested |= self.suggest_dereferences(&obligation, &mut err, trait_predicate);
|
||||
suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate);
|
||||
let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
|
||||
self.suggest_floating_point_literal(&obligation, &mut err, leaf_trait_ref);
|
||||
self.suggest_dereferencing_index(&obligation, &mut err, leaf_trait_predicate);
|
||||
suggested |= self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate);
|
||||
suggested |= self.suggest_fn_call(&obligation, &mut err, leaf_trait_predicate);
|
||||
let impl_candidates = self.find_similar_impl_candidates(leaf_trait_predicate);
|
||||
suggested = if let &[cand] = &impl_candidates[..] {
|
||||
let cand = cand.trait_ref;
|
||||
if let (ty::FnPtr(_), ty::FnDef(..)) =
|
||||
(cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind())
|
||||
(cand.self_ty().kind(), main_trait_ref.self_ty().skip_binder().kind())
|
||||
{
|
||||
err.span_suggestion(
|
||||
span.shrink_to_hi(),
|
||||
@ -702,31 +705,31 @@ fn report_selection_error(
|
||||
false
|
||||
} || suggested;
|
||||
suggested |=
|
||||
self.suggest_remove_reference(&obligation, &mut err, trait_predicate);
|
||||
self.suggest_remove_reference(&obligation, &mut err, leaf_trait_predicate);
|
||||
suggested |= self.suggest_semicolon_removal(
|
||||
&obligation,
|
||||
&mut err,
|
||||
span,
|
||||
trait_predicate,
|
||||
leaf_trait_predicate,
|
||||
);
|
||||
self.note_version_mismatch(&mut err, &trait_ref);
|
||||
self.note_version_mismatch(&mut err, leaf_trait_ref);
|
||||
self.suggest_remove_await(&obligation, &mut err);
|
||||
self.suggest_derive(&obligation, &mut err, trait_predicate);
|
||||
self.suggest_derive(&obligation, &mut err, leaf_trait_predicate);
|
||||
|
||||
if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() {
|
||||
if Some(leaf_trait_ref.def_id()) == tcx.lang_items().try_trait() {
|
||||
self.suggest_await_before_try(
|
||||
&mut err,
|
||||
&obligation,
|
||||
trait_predicate,
|
||||
leaf_trait_predicate,
|
||||
span,
|
||||
);
|
||||
}
|
||||
|
||||
if self.suggest_add_clone_to_arg(&obligation, &mut err, trait_predicate) {
|
||||
if self.suggest_add_clone_to_arg(&obligation, &mut err, leaf_trait_predicate) {
|
||||
return err.emit();
|
||||
}
|
||||
|
||||
if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) {
|
||||
if self.suggest_impl_trait(&mut err, &obligation, leaf_trait_predicate) {
|
||||
return err.emit();
|
||||
}
|
||||
|
||||
@ -741,9 +744,9 @@ fn report_selection_error(
|
||||
);
|
||||
}
|
||||
|
||||
let is_fn_trait = tcx.is_fn_trait(trait_ref.def_id());
|
||||
let is_fn_trait = tcx.is_fn_trait(leaf_trait_ref.def_id());
|
||||
let is_target_feature_fn = if let ty::FnDef(def_id, _) =
|
||||
*trait_ref.skip_binder().self_ty().kind()
|
||||
*leaf_trait_ref.skip_binder().self_ty().kind()
|
||||
{
|
||||
!self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
|
||||
} else {
|
||||
@ -757,8 +760,7 @@ fn report_selection_error(
|
||||
|
||||
self.try_to_add_help_message(
|
||||
&obligation,
|
||||
trait_ref,
|
||||
&trait_predicate,
|
||||
leaf_trait_predicate,
|
||||
&mut err,
|
||||
span,
|
||||
is_fn_trait,
|
||||
@ -769,17 +771,17 @@ fn report_selection_error(
|
||||
// Changing mutability doesn't make a difference to whether we have
|
||||
// an `Unsize` impl (Fixes ICE in #71036)
|
||||
if !is_unsize {
|
||||
self.suggest_change_mut(&obligation, &mut err, trait_predicate);
|
||||
self.suggest_change_mut(&obligation, &mut err, leaf_trait_predicate);
|
||||
}
|
||||
|
||||
// If this error is due to `!: Trait` not implemented but `(): Trait` is
|
||||
// implemented, and fallback has occurred, then it could be due to a
|
||||
// variable that used to fallback to `()` now falling back to `!`. Issue a
|
||||
// note informing about the change in behaviour.
|
||||
if trait_predicate.skip_binder().self_ty().is_never()
|
||||
if leaf_trait_predicate.skip_binder().self_ty().is_never()
|
||||
&& self.fallback_has_occurred
|
||||
{
|
||||
let predicate = trait_predicate.map_bound(|trait_pred| {
|
||||
let predicate = leaf_trait_predicate.map_bound(|trait_pred| {
|
||||
trait_pred.with_self_ty(self.tcx, tcx.types.unit)
|
||||
});
|
||||
let unit_obligation = obligation.with(tcx, predicate);
|
||||
@ -794,8 +796,8 @@ fn report_selection_error(
|
||||
}
|
||||
}
|
||||
|
||||
self.explain_hrtb_projection(&mut err, trait_predicate, obligation.param_env, &obligation.cause);
|
||||
self.suggest_desugaring_async_fn_in_trait(&mut err, trait_ref);
|
||||
self.explain_hrtb_projection(&mut err, leaf_trait_predicate, obligation.param_env, &obligation.cause);
|
||||
self.suggest_desugaring_async_fn_in_trait(&mut err, main_trait_ref);
|
||||
|
||||
// Return early if the trait is Debug or Display and the invocation
|
||||
// originates within a standard library macro, because the output
|
||||
@ -813,15 +815,13 @@ fn report_selection_error(
|
||||
|
||||
if in_std_macro
|
||||
&& matches!(
|
||||
self.tcx.get_diagnostic_name(trait_ref.def_id()),
|
||||
self.tcx.get_diagnostic_name(leaf_trait_ref.def_id()),
|
||||
Some(sym::Debug | sym::Display)
|
||||
)
|
||||
{
|
||||
return err.emit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
@ -2236,11 +2236,7 @@ fn get_parent_trait_ref(
|
||||
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
|
||||
/// with the same path as `trait_ref`, a help message about
|
||||
/// a probable version mismatch is added to `err`
|
||||
fn note_version_mismatch(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
trait_ref: &ty::PolyTraitRef<'tcx>,
|
||||
) -> bool {
|
||||
fn note_version_mismatch(&self, err: &mut Diag<'_>, trait_ref: ty::PolyTraitRef<'tcx>) -> bool {
|
||||
let get_trait_impls = |trait_def_id| {
|
||||
let mut trait_impls = vec![];
|
||||
self.tcx.for_each_relevant_impl(
|
||||
@ -3060,7 +3056,7 @@ fn is_recursive_obligation(
|
||||
|
||||
fn get_standard_error_message(
|
||||
&self,
|
||||
trait_predicate: &ty::PolyTraitPredicate<'tcx>,
|
||||
trait_predicate: ty::PolyTraitPredicate<'tcx>,
|
||||
message: Option<String>,
|
||||
predicate_is_const: bool,
|
||||
append_const_msg: Option<AppendConstMessage>,
|
||||
@ -3231,8 +3227,7 @@ fn add_tuple_trait_message(
|
||||
fn try_to_add_help_message(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_predicate: &ty::PolyTraitPredicate<'tcx>,
|
||||
trait_predicate: ty::PolyTraitPredicate<'tcx>,
|
||||
err: &mut Diag<'_>,
|
||||
span: Span,
|
||||
is_fn_trait: bool,
|
||||
@ -3249,16 +3244,22 @@ fn try_to_add_help_message(
|
||||
};
|
||||
|
||||
// Try to report a help message
|
||||
let trait_def_id = trait_predicate.def_id();
|
||||
if is_fn_trait
|
||||
&& let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
|
||||
obligation.param_env,
|
||||
trait_ref.self_ty(),
|
||||
trait_predicate.self_ty(),
|
||||
trait_predicate.skip_binder().polarity,
|
||||
)
|
||||
{
|
||||
self.add_help_message_for_fn_trait(trait_ref, err, implemented_kind, params);
|
||||
} else if !trait_ref.has_non_region_infer()
|
||||
&& self.predicate_can_apply(obligation.param_env, *trait_predicate)
|
||||
self.add_help_message_for_fn_trait(
|
||||
trait_predicate.to_poly_trait_ref(),
|
||||
err,
|
||||
implemented_kind,
|
||||
params,
|
||||
);
|
||||
} else if !trait_predicate.has_non_region_infer()
|
||||
&& self.predicate_can_apply(obligation.param_env, trait_predicate)
|
||||
{
|
||||
// If a where-clause may be useful, remind the
|
||||
// user that they can add it.
|
||||
@ -3269,25 +3270,25 @@ fn try_to_add_help_message(
|
||||
// which is somewhat confusing.
|
||||
self.suggest_restricting_param_bound(
|
||||
err,
|
||||
*trait_predicate,
|
||||
trait_predicate,
|
||||
None,
|
||||
obligation.cause.body_id,
|
||||
);
|
||||
} else if trait_ref.def_id().is_local()
|
||||
&& self.tcx.trait_impls_of(trait_ref.def_id()).is_empty()
|
||||
&& !self.tcx.trait_is_auto(trait_ref.def_id())
|
||||
&& !self.tcx.trait_is_alias(trait_ref.def_id())
|
||||
} else if trait_def_id.is_local()
|
||||
&& self.tcx.trait_impls_of(trait_def_id).is_empty()
|
||||
&& !self.tcx.trait_is_auto(trait_def_id)
|
||||
&& !self.tcx.trait_is_alias(trait_def_id)
|
||||
{
|
||||
err.span_help(
|
||||
self.tcx.def_span(trait_ref.def_id()),
|
||||
self.tcx.def_span(trait_def_id),
|
||||
crate::fluent_generated::trait_selection_trait_has_no_impls,
|
||||
);
|
||||
} else if !suggested && !unsatisfied_const {
|
||||
// Can't show anything else useful, try to find similar impls.
|
||||
let impl_candidates = self.find_similar_impl_candidates(*trait_predicate);
|
||||
let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
|
||||
if !self.report_similar_impl_candidates(
|
||||
&impl_candidates,
|
||||
trait_ref,
|
||||
trait_predicate.to_poly_trait_ref(),
|
||||
body_def_id,
|
||||
err,
|
||||
true,
|
||||
@ -3295,7 +3296,7 @@ fn try_to_add_help_message(
|
||||
) {
|
||||
self.report_similar_impl_candidates_for_root_obligation(
|
||||
obligation,
|
||||
*trait_predicate,
|
||||
trait_predicate,
|
||||
body_def_id,
|
||||
err,
|
||||
);
|
||||
@ -3304,7 +3305,7 @@ fn try_to_add_help_message(
|
||||
self.suggest_convert_to_slice(
|
||||
err,
|
||||
obligation,
|
||||
trait_ref,
|
||||
trait_predicate.to_poly_trait_ref(),
|
||||
impl_candidates.as_slice(),
|
||||
span,
|
||||
);
|
||||
@ -3369,7 +3370,7 @@ fn add_help_message_for_fn_trait(
|
||||
|
||||
fn maybe_add_note_for_unsatisfied_const(
|
||||
&self,
|
||||
_trait_predicate: &ty::PolyTraitPredicate<'tcx>,
|
||||
_trait_predicate: ty::PolyTraitPredicate<'tcx>,
|
||||
_err: &mut Diag<'_>,
|
||||
_span: Span,
|
||||
) -> UnsatisfiedConst {
|
||||
|
@ -194,7 +194,7 @@ fn predicates_reference_self(
|
||||
predicates
|
||||
.predicates
|
||||
.iter()
|
||||
.map(|&(predicate, sp)| (predicate.instantiate_supertrait(tcx, &trait_ref), sp))
|
||||
.map(|&(predicate, sp)| (predicate.instantiate_supertrait(tcx, trait_ref), sp))
|
||||
.filter_map(|predicate| predicate_references_self(tcx, predicate))
|
||||
.collect()
|
||||
}
|
||||
|
@ -1866,7 +1866,7 @@ fn candidate_should_be_dropped_in_favor_of(
|
||||
// the param_env so that it can be given the lowest priority. See
|
||||
// #50825 for the motivation for this.
|
||||
let is_global =
|
||||
|cand: &ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars();
|
||||
|cand: ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars();
|
||||
|
||||
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
|
||||
// `DiscriminantKindCandidate`, `ConstDestructCandidate`
|
||||
@ -1909,7 +1909,7 @@ fn candidate_should_be_dropped_in_favor_of(
|
||||
}
|
||||
|
||||
(
|
||||
ParamCandidate(ref other_cand),
|
||||
ParamCandidate(other_cand),
|
||||
ImplCandidate(..)
|
||||
| AutoImplCandidate
|
||||
| ClosureCandidate { .. }
|
||||
@ -1934,12 +1934,12 @@ fn candidate_should_be_dropped_in_favor_of(
|
||||
//
|
||||
// Global bounds from the where clause should be ignored
|
||||
// here (see issue #50825).
|
||||
DropVictim::drop_if(!is_global(other_cand))
|
||||
DropVictim::drop_if(!is_global(*other_cand))
|
||||
}
|
||||
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref victim_cand)) => {
|
||||
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(victim_cand)) => {
|
||||
// Prefer these to a global where-clause bound
|
||||
// (see issue #50825).
|
||||
if is_global(victim_cand) { DropVictim::Yes } else { DropVictim::No }
|
||||
if is_global(*victim_cand) { DropVictim::Yes } else { DropVictim::No }
|
||||
}
|
||||
(
|
||||
ImplCandidate(_)
|
||||
@ -1957,12 +1957,12 @@ fn candidate_should_be_dropped_in_favor_of(
|
||||
| TraitUpcastingUnsizeCandidate(_)
|
||||
| BuiltinCandidate { has_nested: true }
|
||||
| TraitAliasCandidate,
|
||||
ParamCandidate(ref victim_cand),
|
||||
ParamCandidate(victim_cand),
|
||||
) => {
|
||||
// Prefer these to a global where-clause bound
|
||||
// (see issue #50825).
|
||||
DropVictim::drop_if(
|
||||
is_global(victim_cand) && other.evaluation.must_apply_modulo_regions(),
|
||||
is_global(*victim_cand) && other.evaluation.must_apply_modulo_regions(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@ fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
|
||||
debug!(?predicates);
|
||||
|
||||
let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
|
||||
pred.instantiate_supertrait(tcx, &trait_ref)
|
||||
pred.instantiate_supertrait(tcx, trait_ref)
|
||||
.as_trait_clause()
|
||||
.map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))
|
||||
});
|
||||
|
@ -125,7 +125,7 @@ fn prepare_vtable_segments_inner<'tcx, T>(
|
||||
.predicates
|
||||
.into_iter()
|
||||
.filter_map(move |(pred, _)| {
|
||||
pred.instantiate_supertrait(tcx, &inner_most_trait_ref).as_trait_clause()
|
||||
pred.instantiate_supertrait(tcx, inner_most_trait_ref).as_trait_clause()
|
||||
});
|
||||
|
||||
// Find an unvisited supertrait
|
||||
|
@ -2,7 +2,7 @@ error[E0277]: the trait bound `&'static u32: Defaulted` is not satisfied
|
||||
--> $DIR/typeck-default-trait-impl-precedence.rs:19:20
|
||||
|
|
||||
LL | is_defaulted::<&'static u32>();
|
||||
| ^^^^^^^^^^^^ the trait `Signed` is not implemented for `&'static u32`, which is required by `&'static u32: Defaulted`
|
||||
| ^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32`, which is required by `&'static u32: Defaulted`
|
||||
|
|
||||
note: required for `&'static u32` to implement `Defaulted`
|
||||
--> $DIR/typeck-default-trait-impl-precedence.rs:10:19
|
||||
|
@ -2,7 +2,7 @@ error[E0277]: the trait bound `i32: Baz<Self>` is not satisfied
|
||||
--> $DIR/assume-gat-normalization-for-nested-goals.rs:9:30
|
||||
|
|
||||
LL | type Bar<T>: Baz<Self> = i32;
|
||||
| ^^^ the trait `Eq<i32>` is not implemented for `i32`, which is required by `i32: Baz<Self>`
|
||||
| ^^^ the trait `Eq<i32>` is not implemented for `<Self as Foo>::Bar<()>`, which is required by `i32: Baz<Self>`
|
||||
|
|
||||
note: required for `i32` to implement `Baz<Self>`
|
||||
--> $DIR/assume-gat-normalization-for-nested-goals.rs:16:23
|
||||
|
@ -46,7 +46,7 @@ error[E0277]: the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfie
|
||||
--> $DIR/nested_impl_trait.rs:6:46
|
||||
|
|
||||
LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Into<u32>`, which is required by `impl Into<u32>: Into<impl Debug>`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`, which is required by `impl Into<u32>: Into<impl Debug>`
|
||||
|
|
||||
= help: the trait `Into<U>` is implemented for `T`
|
||||
= note: required for `impl Into<u32>` to implement `Into<impl Debug>`
|
||||
@ -55,7 +55,7 @@ error[E0277]: the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfie
|
||||
--> $DIR/nested_impl_trait.rs:19:34
|
||||
|
|
||||
LL | fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Into<u32>`, which is required by `impl Into<u32>: Into<impl Debug>`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`, which is required by `impl Into<u32>: Into<impl Debug>`
|
||||
|
|
||||
= help: the trait `Into<U>` is implemented for `T`
|
||||
= note: required for `impl Into<u32>` to implement `Into<impl Debug>`
|
||||
|
@ -4,7 +4,7 @@ error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads sa
|
||||
LL | assert_send::<&'static (dyn Dummy + 'static)>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
|
||||
|
|
||||
= help: the trait `Sync` is not implemented for `&'static (dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send`
|
||||
= help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send`
|
||||
= note: required for `&'static (dyn Dummy + 'static)` to implement `Send`
|
||||
note: required by a bound in `assert_send`
|
||||
--> $DIR/kindck-send-object.rs:5:18
|
||||
|
@ -4,7 +4,7 @@ error[E0277]: `&'a (dyn Dummy + 'a)` cannot be sent between threads safely
|
||||
LL | assert_send::<&'a dyn Dummy>();
|
||||
| ^^^^^^^^^^^^^ `&'a (dyn Dummy + 'a)` cannot be sent between threads safely
|
||||
|
|
||||
= help: the trait `Sync` is not implemented for `&'a (dyn Dummy + 'a)`, which is required by `&'a (dyn Dummy + 'a): Send`
|
||||
= help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)`, which is required by `&'a (dyn Dummy + 'a): Send`
|
||||
= note: required for `&'a (dyn Dummy + 'a)` to implement `Send`
|
||||
note: required by a bound in `assert_send`
|
||||
--> $DIR/kindck-send-object1.rs:5:18
|
||||
|
@ -4,7 +4,7 @@ error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads sa
|
||||
LL | assert_send::<&'static dyn Dummy>();
|
||||
| ^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
|
||||
|
|
||||
= help: the trait `Sync` is not implemented for `&'static (dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send`
|
||||
= help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send`
|
||||
= note: required for `&'static (dyn Dummy + 'static)` to implement `Send`
|
||||
note: required by a bound in `assert_send`
|
||||
--> $DIR/kindck-send-object2.rs:3:18
|
||||
|
@ -4,7 +4,7 @@ error[E0277]: `&mut &mut &mut &mut Vec<i32>` is not an iterator
|
||||
LL | for _ in &mut &mut v {}
|
||||
| ^^^^^^^^^^^ `&mut &mut &mut &mut Vec<i32>` is not an iterator
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `&mut &mut &mut &mut Vec<i32>`, which is required by `&mut &mut &mut &mut Vec<i32>: IntoIterator`
|
||||
= help: the trait `Iterator` is not implemented for `Vec<i32>`, which is required by `&mut &mut &mut &mut Vec<i32>: IntoIterator`
|
||||
= note: required for `&mut Vec<i32>` to implement `Iterator`
|
||||
= note: 3 redundant requirements hidden
|
||||
= note: required for `&mut &mut &mut &mut Vec<i32>` to implement `Iterator`
|
||||
@ -21,7 +21,7 @@ error[E0277]: `&mut &mut &mut [u8; 1]` is not an iterator
|
||||
LL | for _ in &mut v {}
|
||||
| ^^^^^^ `&mut &mut &mut [u8; 1]` is not an iterator
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `&mut &mut &mut [u8; 1]`, which is required by `&mut &mut &mut [u8; 1]: IntoIterator`
|
||||
= help: the trait `Iterator` is not implemented for `[u8; 1]`, which is required by `&mut &mut &mut [u8; 1]: IntoIterator`
|
||||
= note: required for `&mut [u8; 1]` to implement `Iterator`
|
||||
= note: 2 redundant requirements hidden
|
||||
= note: required for `&mut &mut &mut [u8; 1]` to implement `Iterator`
|
||||
|
@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
|
||||
LL | is_send(foo());
|
||||
| ^^^^^ future returned by `foo` is not `Send`
|
||||
|
|
||||
= help: the trait `Sync` is not implemented for `impl Future<Output = ()>`, which is required by `impl Future<Output = ()>: Send`
|
||||
= help: the trait `Sync` is not implemented for `NotSync`, which is required by `impl Future<Output = ()>: Send`
|
||||
note: future is not `Send` as this value is used across an await
|
||||
--> $DIR/auto-with-drop_tracking_mir.rs:16:11
|
||||
|
|
||||
|
@ -4,6 +4,11 @@ error[E0277]: the trait bound `(): Foo` is not satisfied
|
||||
LL | needs_foo::<()>();
|
||||
| ^^ the trait `Bar` is not implemented for `()`, which is required by `(): Foo`
|
||||
|
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/point-at-failing-nested.rs:4:1
|
||||
|
|
||||
LL | trait Bar {}
|
||||
| ^^^^^^^^^
|
||||
note: required for `()` to implement `Foo`
|
||||
--> $DIR/point-at-failing-nested.rs:9:12
|
||||
|
|
||||
|
@ -6,6 +6,11 @@ LL | needs_foo(());
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/where-clause-doesnt-apply.rs:2:1
|
||||
|
|
||||
LL | trait Bar {}
|
||||
| ^^^^^^^^^
|
||||
note: required for `()` to implement `Foo`
|
||||
--> $DIR/where-clause-doesnt-apply.rs:4:9
|
||||
|
|
||||
|
@ -2,7 +2,7 @@ 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<'_>`
|
||||
| -------- ^ the trait `Fn(char)` is not implemented for `char`, which is required by `&char: Pattern<'_>`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
|
@ -2,7 +2,7 @@ error[E0277]: `&u8` cannot be safely transmuted into `&UnsafeCell<u8>`
|
||||
--> $DIR/unsafecell.rs:27:50
|
||||
|
|
||||
LL | assert::is_maybe_transmutable::<&'static u8, &'static UnsafeCell<u8>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `&'static UnsafeCell<u8>`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `UnsafeCell<u8>`
|
||||
|
|
||||
note: required by a bound in `is_maybe_transmutable`
|
||||
--> $DIR/unsafecell.rs:12:14
|
||||
@ -17,7 +17,7 @@ error[E0277]: `&UnsafeCell<u8>` cannot be safely transmuted into `&UnsafeCell<u8
|
||||
--> $DIR/unsafecell.rs:29:62
|
||||
|
|
||||
LL | assert::is_maybe_transmutable::<&'static UnsafeCell<u8>, &'static UnsafeCell<u8>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `&'static UnsafeCell<u8>`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `UnsafeCell<u8>`
|
||||
|
|
||||
note: required by a bound in `is_maybe_transmutable`
|
||||
--> $DIR/unsafecell.rs:12:14
|
||||
|
16
tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs
Normal file
16
tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs
Normal file
@ -0,0 +1,16 @@
|
||||
trait Foo<'s> {}
|
||||
|
||||
impl<'s> Foo<'s> for () {}
|
||||
|
||||
struct Bar;
|
||||
|
||||
impl<'s, T: Foo<'s>> From<T> for Bar {
|
||||
fn from(_: T) -> Self {
|
||||
Bar
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _: Bar = ((),).into();
|
||||
//~^ ERROR he trait bound `((),): Into<Bar>` is not satisfied
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
error[E0277]: the trait bound `((),): Into<Bar>` is not satisfied
|
||||
--> $DIR/suggest-similar-impls-for-root-obligation.rs:14:24
|
||||
|
|
||||
LL | let _: Bar = ((),).into();
|
||||
| ^^^^ the trait `Foo<'_>` is not implemented for `((),)`, which is required by `((),): Into<_>`
|
||||
|
|
||||
= help: the trait `Foo<'_>` is implemented for `()`
|
||||
= help: for that trait implementation, expected `()`, found `((),)`
|
||||
note: required for `Bar` to implement `From<((),)>`
|
||||
--> $DIR/suggest-similar-impls-for-root-obligation.rs:7:22
|
||||
|
|
||||
LL | impl<'s, T: Foo<'s>> From<T> for Bar {
|
||||
| ------- ^^^^^^^ ^^^
|
||||
| |
|
||||
| unsatisfied trait bound introduced here
|
||||
= note: required for `((),)` to implement `Into<Bar>`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Reference in New Issue
Block a user