@@ -54,9 +54,19 @@ pub struct MismatchedProjectionTypes<'tcx> {
5454
5555#[ derive( PartialEq , Eq , Debug ) ]
5656enum ProjectionTyCandidate < ' tcx > {
57+ // from a where-clause in the env or object type
5758 ParamEnv ( ty:: PolyProjectionPredicate < ' tcx > ) ,
59+
60+ // from the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C
61+ TraitDef ( ty:: PolyProjectionPredicate < ' tcx > ) ,
62+
63+ // defined in an impl
5864 Impl ( VtableImplData < ' tcx , PredicateObligation < ' tcx > > ) ,
65+
66+ // closure return type
5967 Closure ( VtableClosureData < ' tcx , PredicateObligation < ' tcx > > ) ,
68+
69+ // fn pointer return type
6070 FnPointer ( Ty < ' tcx > ) ,
6171}
6272
@@ -491,7 +501,11 @@ fn project_type<'cx,'tcx>(
491501 candidates. vec. len( ) ,
492502 candidates. ambiguous) ;
493503
494- // We probably need some winnowing logic similar to select here.
504+ // Inherent ambiguity that prevents us from even enumerating the
505+ // candidates.
506+ if candidates. ambiguous {
507+ return Err ( ProjectionTyError :: TooManyCandidates ) ;
508+ }
495509
496510 // Drop duplicates.
497511 //
@@ -512,10 +526,30 @@ fn project_type<'cx,'tcx>(
512526 }
513527 }
514528
515- if candidates. ambiguous || candidates. vec . len ( ) > 1 {
516- return Err ( ProjectionTyError :: TooManyCandidates ) ;
529+ // Prefer where-clauses. As in select, if there are multiple
530+ // candidates, we prefer where-clause candidates over impls. This
531+ // may seem a bit surprising, since impls are the source of
532+ // "truth" in some sense, but in fact some of the impls that SEEM
533+ // applicable are not, because of nested obligations. Where
534+ // clauses are the safer choice. See the comment on
535+ // `select::SelectionCandidate` and #21974 for more details.
536+ if candidates. vec . len ( ) > 1 {
537+ debug ! ( "retaining param-env candidates only from {:?}" , candidates. vec) ;
538+ candidates. vec . retain ( |c| match * c {
539+ ProjectionTyCandidate :: ParamEnv ( ..) => true ,
540+ ProjectionTyCandidate :: Impl ( ..) |
541+ ProjectionTyCandidate :: Closure ( ..) |
542+ ProjectionTyCandidate :: TraitDef ( ..) |
543+ ProjectionTyCandidate :: FnPointer ( ..) => false ,
544+ } ) ;
545+ debug ! ( "resulting candidate set: {:?}" , candidates. vec) ;
546+ if candidates. vec . len ( ) != 1 {
547+ return Err ( ProjectionTyError :: TooManyCandidates ) ;
548+ }
517549 }
518550
551+ assert ! ( candidates. vec. len( ) <= 1 ) ;
552+
519553 match candidates. vec . pop ( ) {
520554 Some ( candidate) => {
521555 let ( ty, obligations) = confirm_candidate ( selcx, obligation, candidate) ;
@@ -538,9 +572,14 @@ fn assemble_candidates_from_param_env<'cx,'tcx>(
538572 obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
539573 candidate_set : & mut ProjectionTyCandidateSet < ' tcx > )
540574{
575+ debug ! ( "assemble_candidates_from_param_env(..)" ) ;
541576 let env_predicates = selcx. param_env ( ) . caller_bounds . iter ( ) . cloned ( ) ;
542- assemble_candidates_from_predicates ( selcx, obligation, obligation_trait_ref,
543- candidate_set, env_predicates) ;
577+ assemble_candidates_from_predicates ( selcx,
578+ obligation,
579+ obligation_trait_ref,
580+ candidate_set,
581+ ProjectionTyCandidate :: ParamEnv ,
582+ env_predicates) ;
544583}
545584
546585/// In the case of a nested projection like <<A as Foo>::FooT as Bar>::BarT, we may find
@@ -559,6 +598,8 @@ fn assemble_candidates_from_trait_def<'cx,'tcx>(
559598 obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
560599 candidate_set : & mut ProjectionTyCandidateSet < ' tcx > )
561600{
601+ debug ! ( "assemble_candidates_from_trait_def(..)" ) ;
602+
562603 // Check whether the self-type is itself a projection.
563604 let trait_ref = match obligation_trait_ref. self_ty ( ) . sty {
564605 ty:: TyProjection ( ref data) => data. trait_ref . clone ( ) ,
@@ -575,15 +616,20 @@ fn assemble_candidates_from_trait_def<'cx,'tcx>(
575616 let trait_predicates = selcx. tcx ( ) . lookup_predicates ( trait_ref. def_id ) ;
576617 let bounds = trait_predicates. instantiate ( selcx. tcx ( ) , trait_ref. substs ) ;
577618 let bounds = elaborate_predicates ( selcx. tcx ( ) , bounds. predicates . into_vec ( ) ) ;
578- assemble_candidates_from_predicates ( selcx, obligation, obligation_trait_ref,
579- candidate_set, bounds)
619+ assemble_candidates_from_predicates ( selcx,
620+ obligation,
621+ obligation_trait_ref,
622+ candidate_set,
623+ ProjectionTyCandidate :: TraitDef ,
624+ bounds)
580625}
581626
582627fn assemble_candidates_from_predicates < ' cx , ' tcx , I > (
583628 selcx : & mut SelectionContext < ' cx , ' tcx > ,
584629 obligation : & ProjectionTyObligation < ' tcx > ,
585630 obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
586631 candidate_set : & mut ProjectionTyCandidateSet < ' tcx > ,
632+ ctor : fn ( ty:: PolyProjectionPredicate < ' tcx > ) -> ProjectionTyCandidate < ' tcx > ,
587633 env_predicates : I )
588634 where I : Iterator < Item =ty:: Predicate < ' tcx > >
589635{
@@ -614,8 +660,7 @@ fn assemble_candidates_from_predicates<'cx,'tcx,I>(
614660 data, is_match, same_name) ;
615661
616662 if is_match {
617- candidate_set. vec . push (
618- ProjectionTyCandidate :: ParamEnv ( data. clone ( ) ) ) ;
663+ candidate_set. vec . push ( ctor ( data. clone ( ) ) ) ;
619664 }
620665 }
621666 _ => { }
@@ -647,8 +692,12 @@ fn assemble_candidates_from_object_type<'cx,'tcx>(
647692 . map ( |p| p. to_predicate ( ) )
648693 . collect ( ) ;
649694 let env_predicates = elaborate_predicates ( selcx. tcx ( ) , env_predicates) ;
650- assemble_candidates_from_predicates ( selcx, obligation, obligation_trait_ref,
651- candidate_set, env_predicates)
695+ assemble_candidates_from_predicates ( selcx,
696+ obligation,
697+ obligation_trait_ref,
698+ candidate_set,
699+ ProjectionTyCandidate :: ParamEnv ,
700+ env_predicates)
652701}
653702
654703fn assemble_candidates_from_impls < ' cx , ' tcx > (
@@ -746,7 +795,8 @@ fn confirm_candidate<'cx,'tcx>(
746795 obligation) ;
747796
748797 match candidate {
749- ProjectionTyCandidate :: ParamEnv ( poly_projection) => {
798+ ProjectionTyCandidate :: ParamEnv ( poly_projection) |
799+ ProjectionTyCandidate :: TraitDef ( poly_projection) => {
750800 confirm_param_env_candidate ( selcx, obligation, poly_projection)
751801 }
752802
0 commit comments