11//! Code for projecting associated types out of trait references.
22
3+ use std:: iter:: Extend ;
34use std:: ops:: ControlFlow ;
45
56use rustc_data_structures:: sso:: SsoHashSet ;
@@ -65,6 +66,7 @@ enum ProjectionCandidate<'tcx> {
6566 Select ( Selection < ' tcx > ) ,
6667}
6768
69+ #[ derive( Debug ) ]
6870enum ProjectionCandidateSet < ' tcx > {
6971 None ,
7072 Single ( ProjectionCandidate < ' tcx > ) ,
@@ -648,15 +650,26 @@ fn project<'cx, 'tcx>(
648650 }
649651
650652 let mut candidates = ProjectionCandidateSet :: None ;
653+ let mut derived_obligations = PredicateObligations :: default ( ) ;
651654
652655 // Make sure that the following procedures are kept in order. ParamEnv
653656 // needs to be first because it has highest priority, and Select checks
654657 // the return value of push_candidate which assumes it's ran at last.
655- assemble_candidates_from_param_env ( selcx, obligation, & mut candidates) ;
658+ assemble_candidates_from_param_env (
659+ selcx,
660+ obligation,
661+ & mut candidates,
662+ & mut derived_obligations,
663+ ) ;
656664
657665 assemble_candidates_from_trait_def ( selcx, obligation, & mut candidates) ;
658666
659- assemble_candidates_from_object_ty ( selcx, obligation, & mut candidates) ;
667+ assemble_candidates_from_object_ty (
668+ selcx,
669+ obligation,
670+ & mut candidates,
671+ & mut derived_obligations,
672+ ) ;
660673
661674 if let ProjectionCandidateSet :: Single ( ProjectionCandidate :: Object ( _) ) = candidates {
662675 // Avoid normalization cycle from selection (see
@@ -669,7 +682,13 @@ fn project<'cx, 'tcx>(
669682
670683 match candidates {
671684 ProjectionCandidateSet :: Single ( candidate) => {
672- confirm_candidate ( selcx, obligation, candidate)
685+ confirm_candidate ( selcx, obligation, candidate) . map ( move |proj| {
686+ if let Projected :: Progress ( progress) = proj {
687+ Projected :: Progress ( progress. with_addl_obligations ( derived_obligations) )
688+ } else {
689+ proj
690+ }
691+ } )
673692 }
674693 ProjectionCandidateSet :: None => {
675694 let tcx = selcx. tcx ( ) ;
@@ -691,14 +710,15 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>(
691710 selcx : & mut SelectionContext < ' cx , ' tcx > ,
692711 obligation : & ProjectionTermObligation < ' tcx > ,
693712 candidate_set : & mut ProjectionCandidateSet < ' tcx > ,
713+ derived_obligations : & mut impl Extend < PredicateObligation < ' tcx > > ,
694714) {
695715 assemble_candidates_from_predicates (
696716 selcx,
697717 obligation,
698718 candidate_set,
699719 ProjectionCandidate :: ParamEnv ,
700720 obligation. param_env . caller_bounds ( ) . iter ( ) ,
701- false ,
721+ derived_obligations ,
702722 ) ;
703723}
704724
@@ -712,6 +732,7 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>(
712732/// ```
713733///
714734/// Here, for example, we could conclude that the result is `i32`.
735+ #[ instrument( level = "debug" , skip( selcx) ) ]
715736fn assemble_candidates_from_trait_def < ' cx , ' tcx > (
716737 selcx : & mut SelectionContext < ' cx , ' tcx > ,
717738 obligation : & ProjectionTermObligation < ' tcx > ,
@@ -774,6 +795,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
774795 selcx : & mut SelectionContext < ' cx , ' tcx > ,
775796 obligation : & ProjectionTermObligation < ' tcx > ,
776797 candidate_set : & mut ProjectionCandidateSet < ' tcx > ,
798+ derived_obligations : & mut impl Extend < PredicateObligation < ' tcx > > ,
777799) {
778800 debug ! ( "assemble_candidates_from_object_ty(..)" ) ;
779801
@@ -806,21 +828,18 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
806828 candidate_set,
807829 ProjectionCandidate :: Object ,
808830 env_predicates,
809- false ,
831+ derived_obligations ,
810832 ) ;
811833}
812834
813- #[ instrument(
814- level = "debug" ,
815- skip( selcx, candidate_set, ctor, env_predicates, potentially_unnormalized_candidates)
816- ) ]
835+ #[ instrument( level = "debug" , skip( selcx, env_predicates, derived_obligations) ) ]
817836fn assemble_candidates_from_predicates < ' cx , ' tcx > (
818837 selcx : & mut SelectionContext < ' cx , ' tcx > ,
819838 obligation : & ProjectionTermObligation < ' tcx > ,
820839 candidate_set : & mut ProjectionCandidateSet < ' tcx > ,
821840 ctor : fn ( ty:: PolyProjectionPredicate < ' tcx > ) -> ProjectionCandidate < ' tcx > ,
822841 env_predicates : impl Iterator < Item = ty:: Clause < ' tcx > > ,
823- potentially_unnormalized_candidates : bool ,
842+ derived_obligations : & mut impl Extend < PredicateObligation < ' tcx > > ,
824843) {
825844 let infcx = selcx. infcx ;
826845 let drcx = DeepRejectCtxt :: relate_rigid_rigid ( selcx. tcx ( ) ) ;
@@ -838,28 +857,39 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
838857 continue ;
839858 }
840859
841- let is_match = infcx. probe ( |_| {
842- selcx. match_projection_projections (
843- obligation,
844- data,
845- potentially_unnormalized_candidates,
846- )
847- } ) ;
860+ let is_match =
861+ infcx. probe ( |_| selcx. match_projection_projections ( obligation, data, false ) ) ;
848862
849863 match is_match {
850864 ProjectionMatchesProjection :: Yes => {
851- candidate_set. push_candidate ( ctor ( data) ) ;
852-
853- if potentially_unnormalized_candidates
854- && !obligation. predicate . has_non_region_infer ( )
865+ debug ! ( ?data, "push" ) ;
866+ if let ProjectionCandidateSet :: Single (
867+ ProjectionCandidate :: ParamEnv ( proj)
868+ | ProjectionCandidate :: Object ( proj)
869+ | ProjectionCandidate :: TraitDef ( proj) ,
870+ ) = candidate_set
855871 {
856- // HACK: Pick the first trait def candidate for a fully
857- // inferred predicate. This is to allow duplicates that
858- // differ only in normalization.
859- return ;
872+ match infcx. commit_if_ok ( |_| {
873+ infcx. at ( & obligation. cause , obligation. param_env ) . eq_with_proj (
874+ DefineOpaqueTypes :: No ,
875+ data. term ( ) ,
876+ proj. term ( ) ,
877+ )
878+ } ) {
879+ Ok ( InferOk { value : ( ) , obligations } ) => {
880+ derived_obligations. extend ( obligations) ;
881+ }
882+ Err ( e) => {
883+ debug ! ( ?e, "refuse to unify candidates" ) ;
884+ candidate_set. push_candidate ( ctor ( data) ) ;
885+ }
886+ }
887+ } else {
888+ candidate_set. push_candidate ( ctor ( data) ) ;
860889 }
861890 }
862891 ProjectionMatchesProjection :: Ambiguous => {
892+ debug ! ( "mark ambiguous" ) ;
863893 candidate_set. mark_ambiguous ( ) ;
864894 }
865895 ProjectionMatchesProjection :: No => { }
@@ -868,7 +898,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
868898 }
869899}
870900
871- #[ instrument( level = "debug" , skip( selcx, obligation , candidate_set ) ) ]
901+ #[ instrument( level = "debug" , skip( selcx) ) ]
872902fn assemble_candidates_from_impls < ' cx , ' tcx > (
873903 selcx : & mut SelectionContext < ' cx , ' tcx > ,
874904 obligation : & ProjectionTermObligation < ' tcx > ,
0 commit comments