about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs11
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs57
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs79
-rw-r--r--compiler/rustc_trait_selection/src/traits/effects.rs21
4 files changed, 154 insertions, 14 deletions
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 14639039ae9..7ba87e180d0 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -737,7 +737,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     applied_do_not_recommend = true;
                 }
             }
-            if let Some((parent_cause, _parent_pred)) = base_cause.parent() {
+            if let Some(parent_cause) = base_cause.parent() {
                 base_cause = parent_cause.clone();
             } else {
                 break;
@@ -797,7 +797,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind()
             && !found_kind.extends(expected_kind)
         {
-            if let Some((_, Some(parent))) = obligation.cause.code().parent() {
+            if let Some((_, Some(parent))) = obligation.cause.code().parent_with_predicate() {
                 // If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
                 trait_ref = parent.to_poly_trait_ref();
             } else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } =
@@ -945,7 +945,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let Some(typeck) = &self.typeck_results else {
             return false;
         };
-        let Some((ObligationCauseCode::QuestionMark, Some(y))) = obligation.cause.code().parent()
+        let Some((ObligationCauseCode::QuestionMark, Some(y))) =
+            obligation.cause.code().parent_with_predicate()
         else {
             return false;
         };
@@ -1198,7 +1199,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         let mut code = obligation.cause.code();
         let mut pred = obligation.predicate.as_trait_clause();
-        while let Some((next_code, next_pred)) = code.parent() {
+        while let Some((next_code, next_pred)) = code.parent_with_predicate() {
             if let Some(pred) = pred {
                 self.enter_forall(pred, |pred| {
                     diag.note(format!(
@@ -2114,7 +2115,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let mut code = obligation.cause.code();
         let mut trait_pred = trait_predicate;
         let mut peeled = false;
-        while let Some((parent_code, parent_trait_pred)) = code.parent() {
+        while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() {
             code = parent_code;
             if let Some(parent_trait_pred) = parent_trait_pred {
                 trait_pred = parent_trait_pred;
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 007a220ae69..9d85ca1dd4d 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -464,7 +464,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
             // Get the root obligation, since the leaf obligation we have may be unhelpful (#87437)
             let mut real_trait_pred = trait_pred;
-            while let Some((parent_code, parent_trait_pred)) = code.parent() {
+            while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() {
                 code = parent_code;
                 if let Some(parent_trait_pred) = parent_trait_pred {
                     real_trait_pred = parent_trait_pred;
@@ -1447,7 +1447,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let mut span = obligation.cause.span;
         let mut trait_pred = trait_pred;
         let mut code = obligation.cause.code();
-        while let Some((c, Some(parent_trait_pred))) = code.parent() {
+        while let Some((c, Some(parent_trait_pred))) = code.parent_with_predicate() {
             // We want the root obligation, in order to detect properly handle
             // `for _ in &mut &mut vec![] {}`.
             code = c;
@@ -3470,6 +3470,59 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     )
                 });
             }
+            ObligationCauseCode::ImplDerivedHost(ref data) => {
+                let self_ty =
+                    self.resolve_vars_if_possible(data.derived.parent_host_pred.self_ty());
+                let msg = format!(
+                    "required for `{self_ty}` to implement `{} {}`",
+                    data.derived.parent_host_pred.skip_binder().constness,
+                    data.derived
+                        .parent_host_pred
+                        .map_bound(|pred| pred.trait_ref)
+                        .print_only_trait_path(),
+                );
+                match tcx.hir().get_if_local(data.impl_def_id) {
+                    Some(Node::Item(hir::Item {
+                        kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
+                        ..
+                    })) => {
+                        let mut spans = vec![self_ty.span];
+                        spans.extend(of_trait.as_ref().map(|t| t.path.span));
+                        let mut spans: MultiSpan = spans.into();
+                        spans.push_span_label(data.span, "unsatisfied trait bound introduced here");
+                        err.span_note(spans, msg);
+                    }
+                    _ => {
+                        err.note(msg);
+                    }
+                }
+                ensure_sufficient_stack(|| {
+                    self.note_obligation_cause_code(
+                        body_id,
+                        err,
+                        data.derived.parent_host_pred,
+                        param_env,
+                        &data.derived.parent_code,
+                        obligated_types,
+                        seen_requirements,
+                        long_ty_file,
+                    )
+                });
+            }
+            ObligationCauseCode::BuiltinDerivedHost(ref data) => {
+                ensure_sufficient_stack(|| {
+                    self.note_obligation_cause_code(
+                        body_id,
+                        err,
+                        data.parent_host_pred,
+                        param_env,
+                        &data.parent_code,
+                        obligated_types,
+                        seen_requirements,
+                        long_ty_file,
+                    )
+                });
+            }
             ObligationCauseCode::WellFormedDerived(ref data) => {
                 let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
                 let parent_predicate = parent_trait_ref;
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index c79a8abca20..7db0f2bb5a7 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -430,6 +430,7 @@ impl<'tcx> BestObligation<'tcx> {
                                     matches!(
                                         nested_goal.source(),
                                         GoalSource::ImplWhereBound
+                                            | GoalSource::AliasBoundConstCondition
                                             | GoalSource::InstantiateHigherRanked
                                             | GoalSource::AliasWellFormed
                                     ) && match self.consider_ambiguities {
@@ -491,8 +492,11 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
         // for normalizes-to.
         let pred_kind = goal.goal().predicate.kind();
         let child_mode = match pred_kind.skip_binder() {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(parent_trait_pred)) => {
-                ChildMode::Trait(pred_kind.rebind(parent_trait_pred))
+            ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
+                ChildMode::Trait(pred_kind.rebind(pred))
+            }
+            ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(pred)) => {
+                ChildMode::Host(pred_kind.rebind(pred))
             }
             ty::PredicateKind::NormalizesTo(normalizes_to)
                 if matches!(
@@ -521,7 +525,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
 
             let obligation;
             match (child_mode, nested_goal.source()) {
-                (ChildMode::Trait(_), GoalSource::Misc) => {
+                (ChildMode::Trait(_) | ChildMode::Host(_), GoalSource::Misc) => {
                     continue;
                 }
                 (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => {
@@ -534,11 +538,25 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
                     ));
                     impl_where_bound_count += 1;
                 }
+                (
+                    ChildMode::Host(parent_host_pred),
+                    GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition,
+                ) => {
+                    obligation = make_obligation(derive_host_cause(
+                        tcx,
+                        candidate.kind(),
+                        self.obligation.cause.clone(),
+                        impl_where_bound_count,
+                        parent_host_pred,
+                    ));
+                    impl_where_bound_count += 1;
+                }
                 // Skip over a higher-ranked predicate.
                 (_, GoalSource::InstantiateHigherRanked) => {
                     obligation = self.obligation.clone();
                 }
-                (ChildMode::PassThrough, _) | (_, GoalSource::AliasWellFormed) => {
+                (ChildMode::PassThrough, _)
+                | (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => {
                     obligation = make_obligation(self.obligation.cause.clone());
                 }
             }
@@ -592,6 +610,10 @@ enum ChildMode<'tcx> {
     // and skip all `GoalSource::Misc`, which represent useless obligations
     // such as alias-eq which may not hold.
     Trait(ty::PolyTraitPredicate<'tcx>),
+    // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
+    // and skip all `GoalSource::Misc`, which represent useless obligations
+    // such as alias-eq which may not hold.
+    Host(ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>),
     // Skip trying to derive an `ObligationCause` from this obligation, and
     // report *all* sub-obligations as if they came directly from the parent
     // obligation.
@@ -633,3 +655,52 @@ fn derive_cause<'tcx>(
     };
     cause
 }
+
+fn derive_host_cause<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
+    mut cause: ObligationCause<'tcx>,
+    idx: usize,
+    parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
+) -> ObligationCause<'tcx> {
+    match candidate_kind {
+        inspect::ProbeKind::TraitCandidate {
+            source: CandidateSource::Impl(impl_def_id),
+            result: _,
+        } => {
+            if let Some((_, span)) = tcx
+                .predicates_of(impl_def_id)
+                .instantiate_identity(tcx)
+                .into_iter()
+                .chain(tcx.const_conditions(impl_def_id).instantiate_identity(tcx).into_iter().map(
+                    |(trait_ref, span)| {
+                        (
+                            trait_ref.to_host_effect_clause(
+                                tcx,
+                                parent_host_pred.skip_binder().constness,
+                            ),
+                            span,
+                        )
+                    },
+                ))
+                .nth(idx)
+            {
+                cause =
+                    cause.derived_host_cause(parent_host_pred, |derived| {
+                        ObligationCauseCode::ImplDerivedHost(Box::new(
+                            traits::ImplDerivedHostCause { derived, impl_def_id, span },
+                        ))
+                    })
+            }
+        }
+        inspect::ProbeKind::TraitCandidate {
+            source: CandidateSource::BuiltinImpl(..),
+            result: _,
+        } => {
+            cause =
+                cause.derived_host_cause(parent_host_pred, ObligationCauseCode::BuiltinDerivedHost);
+        }
+        _ => {}
+    };
+    cause
+}
diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs
index 91484ef99db..0ac24eb54e7 100644
--- a/compiler/rustc_trait_selection/src/traits/effects.rs
+++ b/compiler/rustc_trait_selection/src/traits/effects.rs
@@ -1,6 +1,8 @@
 use rustc_hir as hir;
 use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
-use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation};
+use rustc_infer::traits::{
+    ImplDerivedHostCause, ImplSource, Obligation, ObligationCauseCode, PredicateObligation,
+};
 use rustc_middle::span_bug;
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::{self, TypingMode};
@@ -248,9 +250,22 @@ fn evaluate_host_effect_from_selection_candiate<'tcx>(
                         tcx.const_conditions(impl_.impl_def_id)
                             .instantiate(tcx, impl_.args)
                             .into_iter()
-                            .map(|(trait_ref, _)| {
-                                obligation.with(
+                            .map(|(trait_ref, span)| {
+                                Obligation::new(
                                     tcx,
+                                    obligation.cause.clone().derived_host_cause(
+                                        ty::Binder::dummy(obligation.predicate),
+                                        |derived| {
+                                            ObligationCauseCode::ImplDerivedHost(Box::new(
+                                                ImplDerivedHostCause {
+                                                    derived,
+                                                    impl_def_id: impl_.impl_def_id,
+                                                    span,
+                                                },
+                                            ))
+                                        },
+                                    ),
+                                    obligation.param_env,
                                     trait_ref
                                         .to_host_effect_clause(tcx, obligation.predicate.constness),
                                 )