@@ -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,7 +111,7 @@ 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
116117struct ProjectionTyCandidateSet < ' tcx > {
@@ -818,45 +819,57 @@ fn project_type<'cx, 'gcx, 'tcx>(
818819 & obligation_trait_ref,
819820 & mut candidates) ;
820821
822+ let decide_commit = |candidates : & mut ProjectionTyCandidateSet < ' tcx > | {
823+ debug ! ( "{} candidates, ambiguous={}" ,
824+ candidates. vec. len( ) ,
825+ candidates. ambiguous) ;
826+
827+ // Prefer where-clauses. As in select, if there are multiple
828+ // candidates, we prefer where-clause candidates over impls. This
829+ // may seem a bit surprising, since impls are the source of
830+ // "truth" in some sense, but in fact some of the impls that SEEM
831+ // applicable are not, because of nested obligations. Where
832+ // clauses are the safer choice. See the comment on
833+ // `select::SelectionCandidate` and #21974 for more details.
834+ if candidates. vec . len ( ) > 1 {
835+ debug ! ( "retaining param-env candidates only from {:?}" , candidates. vec) ;
836+ candidates. vec . retain ( |c| match * c {
837+ ProjectionTyCandidate :: ParamEnv ( ..) => true ,
838+ ProjectionTyCandidate :: TraitDef ( ..) |
839+ ProjectionTyCandidate :: Select ( ..) => false ,
840+ } ) ;
841+ debug ! ( "resulting candidate set: {:?}" , candidates. vec) ;
842+ if candidates. vec . len ( ) != 1 {
843+ candidates. ambiguous = true ;
844+ return false ;
845+ }
846+ }
847+
848+ assert ! ( candidates. vec. len( ) <= 1 ) ;
849+ match candidates. vec . get ( 0 ) {
850+ Some ( & ProjectionTyCandidate :: Select ( ..) ) => true ,
851+ _ => false ,
852+ }
853+ } ;
854+
855+ // Note that at here, if `ProjectionTyCandidate::Select` is not going to be
856+ // a valid candidate, the closure is not executed at all. There are two cases,
857+ // one being trait selection error, and another being ambiguous candidates.
858+ // We handle both by the early return below.
821859 if let Err ( e) = assemble_candidates_from_impls ( selcx,
822860 obligation,
823861 & obligation_trait_ref,
824- & mut candidates) {
862+ & mut candidates,
863+ decide_commit) {
825864 return Err ( ProjectionTyError :: TraitSelectionError ( e) ) ;
826865 }
827866
828- debug ! ( "{} candidates, ambiguous={}" ,
829- candidates. vec. len( ) ,
830- candidates. ambiguous) ;
831-
832867 // Inherent ambiguity that prevents us from even enumerating the
833868 // candidates.
834869 if candidates. ambiguous {
835870 return Err ( ProjectionTyError :: TooManyCandidates ) ;
836871 }
837872
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 ) ;
859-
860873 match candidates. vec . pop ( ) {
861874 Some ( candidate) => {
862875 Ok ( ProjectedTy :: Progress (
@@ -952,7 +965,7 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
952965 debug ! ( "assemble_candidates_from_predicates: predicate={:?}" ,
953966 predicate) ;
954967 match predicate {
955- ty:: Predicate :: Projection ( ref data) => {
968+ ty:: Predicate :: Projection ( data) => {
956969 let same_def_id =
957970 data. 0 . projection_ty . item_def_id == obligation. predicate . item_def_id ;
958971
@@ -975,26 +988,33 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
975988 data, is_match, same_def_id) ;
976989
977990 if is_match {
978- candidate_set. vec . push ( ctor ( data. clone ( ) ) ) ;
991+ candidate_set. vec . push ( ctor ( data) ) ;
979992 }
980993 }
981- _ => { }
994+ _ => { }
982995 }
983996 }
984997}
985998
986- fn assemble_candidates_from_impls < ' cx , ' gcx , ' tcx > (
999+ enum NoImplCandidateError < ' tcx > {
1000+ CanceledCommit ,
1001+ SelectionError ( SelectionError < ' tcx > ) ,
1002+ }
1003+
1004+ fn assemble_candidates_from_impls < ' cx , ' gcx , ' tcx ,
1005+ F : FnOnce ( & mut ProjectionTyCandidateSet < ' tcx > ) -> bool > (
9871006 selcx : & mut SelectionContext < ' cx , ' gcx , ' tcx > ,
9881007 obligation : & ProjectionTyObligation < ' tcx > ,
9891008 obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
990- candidate_set : & mut ProjectionTyCandidateSet < ' tcx > )
1009+ candidate_set : & mut ProjectionTyCandidateSet < ' tcx > ,
1010+ decide_commit : F )
9911011 -> Result < ( ) , SelectionError < ' tcx > >
9921012{
9931013 // If we are resolving `<T as TraitRef<...>>::Item == Type`,
9941014 // start out by selecting the predicate `T as TraitRef<...>`:
9951015 let poly_trait_ref = obligation_trait_ref. to_poly_trait_ref ( ) ;
9961016 let trait_obligation = obligation. with ( poly_trait_ref. to_poly_trait_predicate ( ) ) ;
997- selcx. infcx ( ) . probe ( |_| {
1017+ match selcx. infcx ( ) . commit_if_ok ( |_| {
9981018 let vtable = match selcx. select ( & trait_obligation) {
9991019 Ok ( Some ( vtable) ) => vtable,
10001020 Ok ( None ) => {
@@ -1004,21 +1024,20 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
10041024 Err ( e) => {
10051025 debug ! ( "assemble_candidates_from_impls: selection error {:?}" ,
10061026 e) ;
1007- return Err ( e ) ;
1027+ return Err ( NoImplCandidateError :: SelectionError ( e ) ) ;
10081028 }
10091029 } ;
10101030
1011- match vtable {
1012- super :: VtableClosure ( _) |
1013- super :: VtableGenerator ( _) |
1014- super :: VtableFnPointer ( _) |
1015- super :: VtableObject ( _) => {
1031+ let eligible = match & vtable {
1032+ & super :: VtableClosure ( _) |
1033+ & super :: VtableGenerator ( _) |
1034+ & super :: VtableFnPointer ( _) |
1035+ & super :: VtableObject ( _) => {
10161036 debug ! ( "assemble_candidates_from_impls: vtable={:?}" ,
10171037 vtable) ;
1018-
1019- candidate_set. vec . push ( ProjectionTyCandidate :: Select ) ;
1038+ true
10201039 }
1021- super :: VtableImpl ( ref impl_data) => {
1040+ & super :: VtableImpl ( ref impl_data) => {
10221041 // We have to be careful when projecting out of an
10231042 // impl because of specialization. If we are not in
10241043 // trans (i.e., projection mode is not "any"), and the
@@ -1062,29 +1081,27 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
10621081 node_item. item . defaultness . has_value ( )
10631082 } else {
10641083 node_item. item . defaultness . is_default ( ) ||
1065- selcx. tcx ( ) . impl_is_default ( node_item. node . def_id ( ) )
1084+ selcx. tcx ( ) . impl_is_default ( node_item. node . def_id ( ) )
10661085 } ;
10671086
10681087 // Only reveal a specializable default if we're past type-checking
10691088 // and the obligations is monomorphic, otherwise passes such as
10701089 // transmute checking and polymorphic MIR optimizations could
10711090 // get a result which isn't correct for all monomorphizations.
1072- let new_candidate = if !is_default {
1073- Some ( ProjectionTyCandidate :: Select )
1091+ if !is_default {
1092+ true
10741093 } else if obligation. param_env . reveal == Reveal :: All {
10751094 assert ! ( !poly_trait_ref. needs_infer( ) ) ;
10761095 if !poly_trait_ref. needs_subst ( ) {
1077- Some ( ProjectionTyCandidate :: Select )
1096+ true
10781097 } else {
1079- None
1098+ false
10801099 }
10811100 } else {
1082- None
1083- } ;
1084-
1085- candidate_set. vec . extend ( new_candidate) ;
1101+ false
1102+ }
10861103 }
1087- super :: VtableParam ( ..) => {
1104+ & super :: VtableParam ( ..) => {
10881105 // This case tell us nothing about the value of an
10891106 // associated type. Consider:
10901107 //
@@ -1110,19 +1127,32 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
11101127 // in the compiler: a trait predicate (`T : SomeTrait`) and a
11111128 // projection. And the projection where clause is handled
11121129 // in `assemble_candidates_from_param_env`.
1130+ false
11131131 }
1114- super :: VtableAutoImpl ( ..) |
1115- super :: VtableBuiltin ( ..) => {
1132+ & super :: VtableAutoImpl ( ..) |
1133+ & super :: VtableBuiltin ( ..) => {
11161134 // These traits have no associated types.
11171135 span_bug ! (
11181136 obligation. cause. span,
11191137 "Cannot project an associated type from `{:?}`" ,
11201138 vtable) ;
11211139 }
1140+ } ;
1141+
1142+ if eligible {
1143+ candidate_set. vec . push ( ProjectionTyCandidate :: Select ( vtable) ) ;
11221144 }
11231145
1124- Ok ( ( ) )
1125- } )
1146+ if decide_commit ( candidate_set) {
1147+ Ok ( ( ) )
1148+ } else {
1149+ Err ( NoImplCandidateError :: CanceledCommit )
1150+ }
1151+ } ) {
1152+ Ok ( ( ) ) => Ok ( ( ) ) ,
1153+ Err ( NoImplCandidateError :: CanceledCommit ) => Ok ( ( ) ) ,
1154+ Err ( NoImplCandidateError :: SelectionError ( e) ) => Err ( e) ,
1155+ }
11261156}
11271157
11281158fn confirm_candidate < ' cx , ' gcx , ' tcx > (
@@ -1142,30 +1172,19 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>(
11421172 confirm_param_env_candidate ( selcx, obligation, poly_projection)
11431173 }
11441174
1145- ProjectionTyCandidate :: Select => {
1146- confirm_select_candidate ( selcx, obligation, obligation_trait_ref)
1175+ ProjectionTyCandidate :: Select ( vtable ) => {
1176+ confirm_select_candidate ( selcx, obligation, obligation_trait_ref, vtable )
11471177 }
11481178 }
11491179}
11501180
11511181fn confirm_select_candidate < ' cx , ' gcx , ' tcx > (
11521182 selcx : & mut SelectionContext < ' cx , ' gcx , ' tcx > ,
11531183 obligation : & ProjectionTyObligation < ' tcx > ,
1154- obligation_trait_ref : & ty:: TraitRef < ' tcx > )
1184+ obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
1185+ vtable : Selection < ' tcx > )
11551186 -> Progress < ' tcx >
11561187{
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-
11691188 match vtable {
11701189 super :: VtableImpl ( data) =>
11711190 confirm_impl_candidate ( selcx, obligation, data) ,
0 commit comments