@@ -54,9 +54,19 @@ pub struct MismatchedProjectionTypes<'tcx> {
54
54
55
55
#[ derive( PartialEq , Eq , Debug ) ]
56
56
enum ProjectionTyCandidate < ' tcx > {
57
+ // from a where-clause in the env or object type
57
58
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
58
64
Impl ( VtableImplData < ' tcx , PredicateObligation < ' tcx > > ) ,
65
+
66
+ // closure return type
59
67
Closure ( VtableClosureData < ' tcx , PredicateObligation < ' tcx > > ) ,
68
+
69
+ // fn pointer return type
60
70
FnPointer ( Ty < ' tcx > ) ,
61
71
}
62
72
@@ -491,7 +501,11 @@ fn project_type<'cx,'tcx>(
491
501
candidates. vec. len( ) ,
492
502
candidates. ambiguous) ;
493
503
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
+ }
495
509
496
510
// Drop duplicates.
497
511
//
@@ -512,10 +526,30 @@ fn project_type<'cx,'tcx>(
512
526
}
513
527
}
514
528
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
+ }
517
549
}
518
550
551
+ assert ! ( candidates. vec. len( ) <= 1 ) ;
552
+
519
553
match candidates. vec . pop ( ) {
520
554
Some ( candidate) => {
521
555
let ( ty, obligations) = confirm_candidate ( selcx, obligation, candidate) ;
@@ -538,9 +572,14 @@ fn assemble_candidates_from_param_env<'cx,'tcx>(
538
572
obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
539
573
candidate_set : & mut ProjectionTyCandidateSet < ' tcx > )
540
574
{
575
+ debug ! ( "assemble_candidates_from_param_env(..)" ) ;
541
576
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) ;
544
583
}
545
584
546
585
/// 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>(
559
598
obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
560
599
candidate_set : & mut ProjectionTyCandidateSet < ' tcx > )
561
600
{
601
+ debug ! ( "assemble_candidates_from_trait_def(..)" ) ;
602
+
562
603
// Check whether the self-type is itself a projection.
563
604
let trait_ref = match obligation_trait_ref. self_ty ( ) . sty {
564
605
ty:: TyProjection ( ref data) => data. trait_ref . clone ( ) ,
@@ -575,15 +616,20 @@ fn assemble_candidates_from_trait_def<'cx,'tcx>(
575
616
let trait_predicates = selcx. tcx ( ) . lookup_predicates ( trait_ref. def_id ) ;
576
617
let bounds = trait_predicates. instantiate ( selcx. tcx ( ) , trait_ref. substs ) ;
577
618
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)
580
625
}
581
626
582
627
fn assemble_candidates_from_predicates < ' cx , ' tcx , I > (
583
628
selcx : & mut SelectionContext < ' cx , ' tcx > ,
584
629
obligation : & ProjectionTyObligation < ' tcx > ,
585
630
obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
586
631
candidate_set : & mut ProjectionTyCandidateSet < ' tcx > ,
632
+ ctor : fn ( ty:: PolyProjectionPredicate < ' tcx > ) -> ProjectionTyCandidate < ' tcx > ,
587
633
env_predicates : I )
588
634
where I : Iterator < Item =ty:: Predicate < ' tcx > >
589
635
{
@@ -614,8 +660,7 @@ fn assemble_candidates_from_predicates<'cx,'tcx,I>(
614
660
data, is_match, same_name) ;
615
661
616
662
if is_match {
617
- candidate_set. vec . push (
618
- ProjectionTyCandidate :: ParamEnv ( data. clone ( ) ) ) ;
663
+ candidate_set. vec . push ( ctor ( data. clone ( ) ) ) ;
619
664
}
620
665
}
621
666
_ => { }
@@ -647,8 +692,12 @@ fn assemble_candidates_from_object_type<'cx,'tcx>(
647
692
. map ( |p| p. to_predicate ( ) )
648
693
. collect ( ) ;
649
694
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)
652
701
}
653
702
654
703
fn assemble_candidates_from_impls < ' cx , ' tcx > (
@@ -746,7 +795,8 @@ fn confirm_candidate<'cx,'tcx>(
746
795
obligation) ;
747
796
748
797
match candidate {
749
- ProjectionTyCandidate :: ParamEnv ( poly_projection) => {
798
+ ProjectionTyCandidate :: ParamEnv ( poly_projection) |
799
+ ProjectionTyCandidate :: TraitDef ( poly_projection) => {
750
800
confirm_param_env_candidate ( selcx, obligation, poly_projection)
751
801
}
752
802
0 commit comments