diff options
| author | Michael Goulet <michael@errs.io> | 2024-05-16 20:29:54 -0400 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2024-05-16 21:08:42 -0400 |
| commit | 119c7bbef7a32b2858b1ab82f0f177ab3f68b0b6 (patch) | |
| tree | 4be9337b3c9bc193aab7bc2399a57c10230fedc6 /compiler/rustc_trait_selection/src/solve | |
| parent | 97bf25c8cf6c7c97c851c6e8bc94fd0824885e6f (diff) | |
| download | rust-119c7bbef7a32b2858b1ab82f0f177ab3f68b0b6.tar.gz rust-119c7bbef7a32b2858b1ab82f0f177ab3f68b0b6.zip | |
Report better WF obligation leaf obligations in new solver
Diffstat (limited to 'compiler/rustc_trait_selection/src/solve')
| -rw-r--r-- | compiler/rustc_trait_selection/src/solve/fulfill.rs | 77 |
1 files changed, 57 insertions, 20 deletions
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>, |
