@@ -16,6 +16,7 @@ use super::translate_substs;
1616use super :: Obligation ;
1717use super :: ObligationCause ;
1818use super :: PredicateObligation ;
19+ use super :: Selection ;
1920use super :: SelectionContext ;
2021use super :: SelectionError ;
2122use super :: VtableClosureData ;
@@ -110,12 +111,59 @@ enum ProjectionTyCandidate<'tcx> {
110111 TraitDef ( ty:: PolyProjectionPredicate < ' tcx > ) ,
111112
112113 // from a "impl" (or a "pseudo-impl" returned by select)
113- Select ,
114+ Select ( Selection < ' tcx > ) ,
114115}
115116
116- struct ProjectionTyCandidateSet < ' tcx > {
117- vec : Vec < ProjectionTyCandidate < ' tcx > > ,
118- ambiguous : bool
117+ enum ProjectionTyCandidateSet < ' tcx > {
118+ None ,
119+ Single ( ProjectionTyCandidate < ' tcx > ) ,
120+ Ambiguous ,
121+ Error ( SelectionError < ' tcx > ) ,
122+ }
123+
124+ impl < ' tcx > ProjectionTyCandidateSet < ' tcx > {
125+ fn mark_ambiguous ( & mut self ) {
126+ * self = ProjectionTyCandidateSet :: Ambiguous ;
127+ }
128+
129+ fn mark_error ( & mut self , err : SelectionError < ' tcx > ) {
130+ * self = ProjectionTyCandidateSet :: Error ( err) ;
131+ }
132+
133+ // Returns true if the push was successful, or false if the candidate
134+ // was discarded -- this could be because of ambiguity, or because
135+ // a higher-priority candidate is already there.
136+ fn push_candidate ( & mut self , candidate : ProjectionTyCandidate < ' tcx > ) -> bool {
137+ use self :: ProjectionTyCandidateSet :: * ;
138+ use self :: ProjectionTyCandidate :: * ;
139+ match self {
140+ None => {
141+ * self = Single ( candidate) ;
142+ true
143+ }
144+ Single ( current) => {
145+ // No duplicates are expected.
146+ assert_ne ! ( current, & candidate) ;
147+ // Prefer where-clauses. As in select, if there are multiple
148+ // candidates, we prefer where-clause candidates over impls. This
149+ // may seem a bit surprising, since impls are the source of
150+ // "truth" in some sense, but in fact some of the impls that SEEM
151+ // applicable are not, because of nested obligations. Where
152+ // clauses are the safer choice. See the comment on
153+ // `select::SelectionCandidate` and #21974 for more details.
154+ match ( current, candidate) {
155+ ( ParamEnv ( ..) , ParamEnv ( ..) ) => { * self = Ambiguous ; }
156+ ( ParamEnv ( ..) , _) => { }
157+ ( _, ParamEnv ( ..) ) => { unreachable ! ( ) ; }
158+ ( _, _) => { * self = Ambiguous ; }
159+ }
160+ false
161+ }
162+ Ambiguous | Error ( ..) => {
163+ false
164+ }
165+ }
166+ }
119167}
120168
121169/// Evaluates constraints of the form:
@@ -803,11 +851,11 @@ fn project_type<'cx, 'gcx, 'tcx>(
803851 return Ok ( ProjectedTy :: Progress ( Progress :: error ( selcx. tcx ( ) ) ) ) ;
804852 }
805853
806- let mut candidates = ProjectionTyCandidateSet {
807- vec : Vec :: new ( ) ,
808- ambiguous : false ,
809- } ;
854+ let mut candidates = ProjectionTyCandidateSet :: None ;
810855
856+ // Make sure that the following procedures are kept in order. ParamEnv
857+ // needs to be first because it has highest priority, and Select checks
858+ // the return value of push_candidate which assumes it's ran at last.
811859 assemble_candidates_from_param_env ( selcx,
812860 obligation,
813861 & obligation_trait_ref,
@@ -818,57 +866,27 @@ fn project_type<'cx, 'gcx, 'tcx>(
818866 & obligation_trait_ref,
819867 & mut candidates) ;
820868
821- if let Err ( e) = assemble_candidates_from_impls ( selcx,
822- obligation,
823- & obligation_trait_ref,
824- & mut candidates) {
825- return Err ( ProjectionTyError :: TraitSelectionError ( e) ) ;
826- }
827-
828- debug ! ( "{} candidates, ambiguous={}" ,
829- candidates. vec. len( ) ,
830- candidates. ambiguous) ;
831-
832- // Inherent ambiguity that prevents us from even enumerating the
833- // candidates.
834- if candidates. ambiguous {
835- return Err ( ProjectionTyError :: TooManyCandidates ) ;
836- }
837-
838- // Prefer where-clauses. As in select, if there are multiple
839- // candidates, we prefer where-clause candidates over impls. This
840- // may seem a bit surprising, since impls are the source of
841- // "truth" in some sense, but in fact some of the impls that SEEM
842- // applicable are not, because of nested obligations. Where
843- // clauses are the safer choice. See the comment on
844- // `select::SelectionCandidate` and #21974 for more details.
845- if candidates. vec . len ( ) > 1 {
846- debug ! ( "retaining param-env candidates only from {:?}" , candidates. vec) ;
847- candidates. vec . retain ( |c| match * c {
848- ProjectionTyCandidate :: ParamEnv ( ..) => true ,
849- ProjectionTyCandidate :: TraitDef ( ..) |
850- ProjectionTyCandidate :: Select => false ,
851- } ) ;
852- debug ! ( "resulting candidate set: {:?}" , candidates. vec) ;
853- if candidates. vec . len ( ) != 1 {
854- return Err ( ProjectionTyError :: TooManyCandidates ) ;
855- }
856- }
857-
858- assert ! ( candidates. vec. len( ) <= 1 ) ;
869+ assemble_candidates_from_impls ( selcx,
870+ obligation,
871+ & obligation_trait_ref,
872+ & mut candidates) ;
873+
874+ match candidates {
875+ ProjectionTyCandidateSet :: Single ( candidate) => Ok ( ProjectedTy :: Progress (
876+ confirm_candidate ( selcx,
877+ obligation,
878+ & obligation_trait_ref,
879+ candidate) ) ) ,
880+ ProjectionTyCandidateSet :: None => Ok ( ProjectedTy :: NoProgress (
881+ selcx. tcx ( ) . mk_projection (
882+ obligation. predicate . item_def_id ,
883+ obligation. predicate . substs ) ) ) ,
884+ // Error occurred while trying to processing impls.
885+ ProjectionTyCandidateSet :: Error ( e) => Err ( ProjectionTyError :: TraitSelectionError ( e) ) ,
886+ // Inherent ambiguity that prevents us from even enumerating the
887+ // candidates.
888+ ProjectionTyCandidateSet :: Ambiguous => Err ( ProjectionTyError :: TooManyCandidates ) ,
859889
860- match candidates. vec . pop ( ) {
861- Some ( candidate) => {
862- Ok ( ProjectedTy :: Progress (
863- confirm_candidate ( selcx,
864- obligation,
865- & obligation_trait_ref,
866- candidate) ) )
867- }
868- None => Ok ( ProjectedTy :: NoProgress (
869- selcx. tcx ( ) . mk_projection (
870- obligation. predicate . item_def_id ,
871- obligation. predicate . substs ) ) )
872890 }
873891}
874892
@@ -918,7 +936,7 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>(
918936 ty:: TyInfer ( ty:: TyVar ( _) ) => {
919937 // If the self-type is an inference variable, then it MAY wind up
920938 // being a projected type, so induce an ambiguity.
921- candidate_set. ambiguous = true ;
939+ candidate_set. mark_ambiguous ( ) ;
922940 return ;
923941 }
924942 _ => { return ; }
@@ -952,7 +970,7 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
952970 debug ! ( "assemble_candidates_from_predicates: predicate={:?}" ,
953971 predicate) ;
954972 match predicate {
955- ty:: Predicate :: Projection ( ref data) => {
973+ ty:: Predicate :: Projection ( data) => {
956974 let same_def_id =
957975 data. 0 . projection_ty . item_def_id == obligation. predicate . item_def_id ;
958976
@@ -975,10 +993,10 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
975993 data, is_match, same_def_id) ;
976994
977995 if is_match {
978- candidate_set. vec . push ( ctor ( data. clone ( ) ) ) ;
996+ candidate_set. push_candidate ( ctor ( data) ) ;
979997 }
980998 }
981- _ => { }
999+ _ => { }
9821000 }
9831001 }
9841002}
@@ -988,37 +1006,36 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
9881006 obligation : & ProjectionTyObligation < ' tcx > ,
9891007 obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
9901008 candidate_set : & mut ProjectionTyCandidateSet < ' tcx > )
991- -> Result < ( ) , SelectionError < ' tcx > >
9921009{
9931010 // If we are resolving `<T as TraitRef<...>>::Item == Type`,
9941011 // start out by selecting the predicate `T as TraitRef<...>`:
9951012 let poly_trait_ref = obligation_trait_ref. to_poly_trait_ref ( ) ;
9961013 let trait_obligation = obligation. with ( poly_trait_ref. to_poly_trait_predicate ( ) ) ;
997- selcx. infcx ( ) . probe ( |_| {
1014+ let _ = selcx. infcx ( ) . commit_if_ok ( |_| {
9981015 let vtable = match selcx. select ( & trait_obligation) {
9991016 Ok ( Some ( vtable) ) => vtable,
10001017 Ok ( None ) => {
1001- candidate_set. ambiguous = true ;
1002- return Ok ( ( ) ) ;
1018+ candidate_set. mark_ambiguous ( ) ;
1019+ return Err ( ( ) ) ;
10031020 }
10041021 Err ( e) => {
10051022 debug ! ( "assemble_candidates_from_impls: selection error {:?}" ,
10061023 e) ;
1007- return Err ( e) ;
1024+ candidate_set. mark_error ( e) ;
1025+ return Err ( ( ) ) ;
10081026 }
10091027 } ;
10101028
1011- match vtable {
1029+ let eligible = match & vtable {
10121030 super :: VtableClosure ( _) |
10131031 super :: VtableGenerator ( _) |
10141032 super :: VtableFnPointer ( _) |
10151033 super :: VtableObject ( _) => {
10161034 debug ! ( "assemble_candidates_from_impls: vtable={:?}" ,
10171035 vtable) ;
1018-
1019- candidate_set. vec . push ( ProjectionTyCandidate :: Select ) ;
1036+ true
10201037 }
1021- super :: VtableImpl ( ref impl_data) => {
1038+ super :: VtableImpl ( impl_data) => {
10221039 // We have to be careful when projecting out of an
10231040 // impl because of specialization. If we are not in
10241041 // trans (i.e., projection mode is not "any"), and the
@@ -1062,27 +1079,25 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
10621079 node_item. item . defaultness . has_value ( )
10631080 } else {
10641081 node_item. item . defaultness . is_default ( ) ||
1065- selcx. tcx ( ) . impl_is_default ( node_item. node . def_id ( ) )
1082+ selcx. tcx ( ) . impl_is_default ( node_item. node . def_id ( ) )
10661083 } ;
10671084
10681085 // Only reveal a specializable default if we're past type-checking
10691086 // and the obligations is monomorphic, otherwise passes such as
10701087 // transmute checking and polymorphic MIR optimizations could
10711088 // get a result which isn't correct for all monomorphizations.
1072- let new_candidate = if !is_default {
1073- Some ( ProjectionTyCandidate :: Select )
1089+ if !is_default {
1090+ true
10741091 } else if obligation. param_env . reveal == Reveal :: All {
10751092 assert ! ( !poly_trait_ref. needs_infer( ) ) ;
10761093 if !poly_trait_ref. needs_subst ( ) {
1077- Some ( ProjectionTyCandidate :: Select )
1094+ true
10781095 } else {
1079- None
1096+ false
10801097 }
10811098 } else {
1082- None
1083- } ;
1084-
1085- candidate_set. vec . extend ( new_candidate) ;
1099+ false
1100+ }
10861101 }
10871102 super :: VtableParam ( ..) => {
10881103 // This case tell us nothing about the value of an
@@ -1110,6 +1125,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
11101125 // in the compiler: a trait predicate (`T : SomeTrait`) and a
11111126 // projection. And the projection where clause is handled
11121127 // in `assemble_candidates_from_param_env`.
1128+ false
11131129 }
11141130 super :: VtableAutoImpl ( ..) |
11151131 super :: VtableBuiltin ( ..) => {
@@ -1119,10 +1135,18 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
11191135 "Cannot project an associated type from `{:?}`" ,
11201136 vtable) ;
11211137 }
1122- }
1138+ } ;
11231139
1124- Ok ( ( ) )
1125- } )
1140+ if eligible {
1141+ if candidate_set. push_candidate ( ProjectionTyCandidate :: Select ( vtable) ) {
1142+ Ok ( ( ) )
1143+ } else {
1144+ Err ( ( ) )
1145+ }
1146+ } else {
1147+ Err ( ( ) )
1148+ }
1149+ } ) ;
11261150}
11271151
11281152fn confirm_candidate < ' cx , ' gcx , ' tcx > (
@@ -1142,30 +1166,19 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>(
11421166 confirm_param_env_candidate ( selcx, obligation, poly_projection)
11431167 }
11441168
1145- ProjectionTyCandidate :: Select => {
1146- confirm_select_candidate ( selcx, obligation, obligation_trait_ref)
1169+ ProjectionTyCandidate :: Select ( vtable ) => {
1170+ confirm_select_candidate ( selcx, obligation, obligation_trait_ref, vtable )
11471171 }
11481172 }
11491173}
11501174
11511175fn confirm_select_candidate < ' cx , ' gcx , ' tcx > (
11521176 selcx : & mut SelectionContext < ' cx , ' gcx , ' tcx > ,
11531177 obligation : & ProjectionTyObligation < ' tcx > ,
1154- obligation_trait_ref : & ty:: TraitRef < ' tcx > )
1178+ obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
1179+ vtable : Selection < ' tcx > )
11551180 -> Progress < ' tcx >
11561181{
1157- let poly_trait_ref = obligation_trait_ref. to_poly_trait_ref ( ) ;
1158- let trait_obligation = obligation. with ( poly_trait_ref. to_poly_trait_predicate ( ) ) ;
1159- let vtable = match selcx. select ( & trait_obligation) {
1160- Ok ( Some ( vtable) ) => vtable,
1161- _ => {
1162- span_bug ! (
1163- obligation. cause. span,
1164- "Failed to select `{:?}`" ,
1165- trait_obligation) ;
1166- }
1167- } ;
1168-
11691182 match vtable {
11701183 super :: VtableImpl ( data) =>
11711184 confirm_impl_candidate ( selcx, obligation, data) ,
0 commit comments