@@ -384,39 +384,64 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
384384 return ControlFlow :: Break ( self . obligation . clone ( ) ) ;
385385 }
386386
387- // FIXME: Could we extract a trait ref from a projection here too?
387+ let tcx = goal . infcx ( ) . tcx ;
388388 // FIXME: Also, what about considering >1 layer up the stack? May be necessary
389389 // for normalizes-to.
390- let Some ( parent_trait_pred) = goal. goal ( ) . predicate . to_opt_poly_trait_pred ( ) else {
391- return ControlFlow :: Break ( self . obligation . clone ( ) ) ;
390+ let pred_kind = goal. goal ( ) . predicate . kind ( ) ;
391+ let child_mode = match pred_kind. skip_binder ( ) {
392+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( parent_trait_pred) ) => {
393+ ChildMode :: Trait ( pred_kind. rebind ( parent_trait_pred) )
394+ }
395+ ty:: PredicateKind :: NormalizesTo ( normalizes_to)
396+ if matches ! (
397+ normalizes_to. alias. kind( tcx) ,
398+ ty:: AliasTermKind :: ProjectionTy | ty:: AliasTermKind :: ProjectionConst
399+ ) =>
400+ {
401+ ChildMode :: Trait ( pred_kind. rebind ( ty:: TraitPredicate {
402+ trait_ref : normalizes_to. alias . trait_ref ( tcx) ,
403+ polarity : ty:: PredicatePolarity :: Positive ,
404+ } ) )
405+ }
406+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: WellFormed ( _) ) => {
407+ ChildMode :: WellFormedObligation
408+ }
409+ _ => {
410+ return ControlFlow :: Break ( self . obligation . clone ( ) ) ;
411+ }
392412 } ;
393413
394- let tcx = goal. infcx ( ) . tcx ;
395414 let mut impl_where_bound_count = 0 ;
396415 for nested_goal in candidate. instantiate_nested_goals ( self . span ( ) ) {
416+ let make_obligation = |cause| Obligation {
417+ cause,
418+ param_env : nested_goal. goal ( ) . param_env ,
419+ predicate : nested_goal. goal ( ) . predicate ,
420+ recursion_depth : self . obligation . recursion_depth + 1 ,
421+ } ;
422+
397423 let obligation;
398- match nested_goal. source ( ) {
399- GoalSource :: Misc => {
424+ match ( child_mode , nested_goal. source ( ) ) {
425+ ( ChildMode :: Trait ( _ ) , GoalSource :: Misc ) => {
400426 continue ;
401427 }
402- GoalSource :: ImplWhereBound => {
403- obligation = Obligation {
404- cause : derive_cause (
405- tcx,
406- candidate. kind ( ) ,
407- self . obligation . cause . clone ( ) ,
408- impl_where_bound_count,
409- parent_trait_pred,
410- ) ,
411- param_env : nested_goal. goal ( ) . param_env ,
412- predicate : nested_goal. goal ( ) . predicate ,
413- recursion_depth : self . obligation . recursion_depth + 1 ,
414- } ;
428+ ( ChildMode :: Trait ( parent_trait_pred) , GoalSource :: ImplWhereBound ) => {
429+ obligation = make_obligation ( derive_cause (
430+ tcx,
431+ candidate. kind ( ) ,
432+ self . obligation . cause . clone ( ) ,
433+ impl_where_bound_count,
434+ parent_trait_pred,
435+ ) ) ;
415436 impl_where_bound_count += 1 ;
416437 }
417- GoalSource :: InstantiateHigherRanked => {
438+ // Skip over a higher-ranked predicate.
439+ ( _, GoalSource :: InstantiateHigherRanked ) => {
418440 obligation = self . obligation . clone ( ) ;
419441 }
442+ ( ChildMode :: WellFormedObligation , _) => {
443+ obligation = make_obligation ( self . obligation . cause . clone ( ) ) ;
444+ }
420445 }
421446
422447 // Skip nested goals that aren't the *reason* for our goal's failure.
@@ -436,6 +461,18 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
436461 }
437462}
438463
464+ #[ derive( Copy , Clone ) ]
465+ enum ChildMode < ' tcx > {
466+ // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
467+ // and skip all `GoalSource::Misc`, which represent useless obligations
468+ // such as alias-eq which may not hold.
469+ Trait ( ty:: PolyTraitPredicate < ' tcx > ) ,
470+ // Skip trying to derive an `ObligationCause` from this obligation, and
471+ // report *all* sub-obligations as if they came directly from the parent
472+ // obligation.
473+ WellFormedObligation ,
474+ }
475+
439476fn derive_cause < ' tcx > (
440477 tcx : TyCtxt < ' tcx > ,
441478 candidate_kind : ProbeKind < ' tcx > ,
0 commit comments