From 119c7bbef7a32b2858b1ab82f0f177ab3f68b0b6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 16 May 2024 20:29:54 -0400 Subject: Report better WF obligation leaf obligations in new solver --- .../rustc_trait_selection/src/solve/fulfill.rs | 77 ++++++++++++++++------ 1 file changed, 57 insertions(+), 20 deletions(-) (limited to 'compiler/rustc_trait_selection/src') diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 3379c1d51a8..625bcf33a16 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -384,39 +384,64 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { return ControlFlow::Break(self.obligation.clone()); } - // FIXME: Could we extract a trait ref from a projection here too? + let tcx = goal.infcx().tcx; // FIXME: Also, what about considering >1 layer up the stack? May be necessary // for normalizes-to. - let Some(parent_trait_pred) = goal.goal().predicate.to_opt_poly_trait_pred() else { - return ControlFlow::Break(self.obligation.clone()); + 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::NormalizesTo(normalizes_to) + if matches!( + normalizes_to.alias.kind(tcx), + ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst + ) => + { + ChildMode::Trait(pred_kind.rebind(ty::TraitPredicate { + trait_ref: normalizes_to.alias.trait_ref(tcx), + polarity: ty::PredicatePolarity::Positive, + })) + } + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => { + ChildMode::WellFormedObligation + } + _ => { + return ControlFlow::Break(self.obligation.clone()); + } }; - let tcx = goal.infcx().tcx; let mut impl_where_bound_count = 0; for nested_goal in candidate.instantiate_nested_goals(self.span()) { + let make_obligation = |cause| Obligation { + cause, + param_env: nested_goal.goal().param_env, + predicate: nested_goal.goal().predicate, + recursion_depth: self.obligation.recursion_depth + 1, + }; + let obligation; - match nested_goal.source() { - GoalSource::Misc => { + match (child_mode, nested_goal.source()) { + (ChildMode::Trait(_), GoalSource::Misc) => { continue; } - GoalSource::ImplWhereBound => { - obligation = Obligation { - cause: derive_cause( - tcx, - candidate.kind(), - self.obligation.cause.clone(), - impl_where_bound_count, - parent_trait_pred, - ), - param_env: nested_goal.goal().param_env, - predicate: nested_goal.goal().predicate, - recursion_depth: self.obligation.recursion_depth + 1, - }; + (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => { + obligation = make_obligation(derive_cause( + tcx, + candidate.kind(), + self.obligation.cause.clone(), + impl_where_bound_count, + parent_trait_pred, + )); impl_where_bound_count += 1; } - GoalSource::InstantiateHigherRanked => { + // Skip over a higher-ranked predicate. + (_, GoalSource::InstantiateHigherRanked) => { obligation = self.obligation.clone(); } + (ChildMode::WellFormedObligation, _) => { + obligation = make_obligation(self.obligation.cause.clone()); + } } // Skip nested goals that aren't the *reason* for our goal's failure. @@ -436,6 +461,18 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { } } +#[derive(Copy, Clone)] +enum ChildMode<'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. + Trait(ty::PolyTraitPredicate<'tcx>), + // Skip trying to derive an `ObligationCause` from this obligation, and + // report *all* sub-obligations as if they came directly from the parent + // obligation. + WellFormedObligation, +} + fn derive_cause<'tcx>( tcx: TyCtxt<'tcx>, candidate_kind: ProbeKind<'tcx>, -- cgit 1.4.1-3-g733a5