@@ -16,6 +16,7 @@ use super::translate_substs;
16
16
use super :: Obligation ;
17
17
use super :: ObligationCause ;
18
18
use super :: PredicateObligation ;
19
+ use super :: Selection ;
19
20
use super :: SelectionContext ;
20
21
use super :: SelectionError ;
21
22
use super :: VtableClosureData ;
@@ -110,7 +111,7 @@ enum ProjectionTyCandidate<'tcx> {
110
111
TraitDef ( ty:: PolyProjectionPredicate < ' tcx > ) ,
111
112
112
113
// from a "impl" (or a "pseudo-impl" returned by select)
113
- Select ,
114
+ Select ( Selection < ' tcx > ) ,
114
115
}
115
116
116
117
struct ProjectionTyCandidateSet < ' tcx > {
@@ -818,45 +819,57 @@ fn project_type<'cx, 'gcx, 'tcx>(
818
819
& obligation_trait_ref,
819
820
& mut candidates) ;
820
821
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.
821
859
if let Err ( e) = assemble_candidates_from_impls ( selcx,
822
860
obligation,
823
861
& obligation_trait_ref,
824
- & mut candidates) {
862
+ & mut candidates,
863
+ decide_commit) {
825
864
return Err ( ProjectionTyError :: TraitSelectionError ( e) ) ;
826
865
}
827
866
828
- debug ! ( "{} candidates, ambiguous={}" ,
829
- candidates. vec. len( ) ,
830
- candidates. ambiguous) ;
831
-
832
867
// Inherent ambiguity that prevents us from even enumerating the
833
868
// candidates.
834
869
if candidates. ambiguous {
835
870
return Err ( ProjectionTyError :: TooManyCandidates ) ;
836
871
}
837
872
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
-
860
873
match candidates. vec . pop ( ) {
861
874
Some ( candidate) => {
862
875
Ok ( ProjectedTy :: Progress (
@@ -952,7 +965,7 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
952
965
debug ! ( "assemble_candidates_from_predicates: predicate={:?}" ,
953
966
predicate) ;
954
967
match predicate {
955
- ty:: Predicate :: Projection ( ref data) => {
968
+ ty:: Predicate :: Projection ( data) => {
956
969
let same_def_id =
957
970
data. 0 . projection_ty . item_def_id == obligation. predicate . item_def_id ;
958
971
@@ -975,26 +988,33 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
975
988
data, is_match, same_def_id) ;
976
989
977
990
if is_match {
978
- candidate_set. vec . push ( ctor ( data. clone ( ) ) ) ;
991
+ candidate_set. vec . push ( ctor ( data) ) ;
979
992
}
980
993
}
981
- _ => { }
994
+ _ => { }
982
995
}
983
996
}
984
997
}
985
998
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 > (
987
1006
selcx : & mut SelectionContext < ' cx , ' gcx , ' tcx > ,
988
1007
obligation : & ProjectionTyObligation < ' tcx > ,
989
1008
obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
990
- candidate_set : & mut ProjectionTyCandidateSet < ' tcx > )
1009
+ candidate_set : & mut ProjectionTyCandidateSet < ' tcx > ,
1010
+ decide_commit : F )
991
1011
-> Result < ( ) , SelectionError < ' tcx > >
992
1012
{
993
1013
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
994
1014
// start out by selecting the predicate `T as TraitRef<...>`:
995
1015
let poly_trait_ref = obligation_trait_ref. to_poly_trait_ref ( ) ;
996
1016
let trait_obligation = obligation. with ( poly_trait_ref. to_poly_trait_predicate ( ) ) ;
997
- selcx. infcx ( ) . probe ( |_| {
1017
+ match selcx. infcx ( ) . commit_if_ok ( |_| {
998
1018
let vtable = match selcx. select ( & trait_obligation) {
999
1019
Ok ( Some ( vtable) ) => vtable,
1000
1020
Ok ( None ) => {
@@ -1004,21 +1024,20 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
1004
1024
Err ( e) => {
1005
1025
debug ! ( "assemble_candidates_from_impls: selection error {:?}" ,
1006
1026
e) ;
1007
- return Err ( e ) ;
1027
+ return Err ( NoImplCandidateError :: SelectionError ( e ) ) ;
1008
1028
}
1009
1029
} ;
1010
1030
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 ( _) => {
1016
1036
debug ! ( "assemble_candidates_from_impls: vtable={:?}" ,
1017
1037
vtable) ;
1018
-
1019
- candidate_set. vec . push ( ProjectionTyCandidate :: Select ) ;
1038
+ true
1020
1039
}
1021
- super :: VtableImpl ( ref impl_data) => {
1040
+ & super :: VtableImpl ( ref impl_data) => {
1022
1041
// We have to be careful when projecting out of an
1023
1042
// impl because of specialization. If we are not in
1024
1043
// trans (i.e., projection mode is not "any"), and the
@@ -1062,29 +1081,27 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
1062
1081
node_item. item . defaultness . has_value ( )
1063
1082
} else {
1064
1083
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 ( ) )
1066
1085
} ;
1067
1086
1068
1087
// Only reveal a specializable default if we're past type-checking
1069
1088
// and the obligations is monomorphic, otherwise passes such as
1070
1089
// transmute checking and polymorphic MIR optimizations could
1071
1090
// 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
1074
1093
} else if obligation. param_env . reveal == Reveal :: All {
1075
1094
assert ! ( !poly_trait_ref. needs_infer( ) ) ;
1076
1095
if !poly_trait_ref. needs_subst ( ) {
1077
- Some ( ProjectionTyCandidate :: Select )
1096
+ true
1078
1097
} else {
1079
- None
1098
+ false
1080
1099
}
1081
1100
} else {
1082
- None
1083
- } ;
1084
-
1085
- candidate_set. vec . extend ( new_candidate) ;
1101
+ false
1102
+ }
1086
1103
}
1087
- super :: VtableParam ( ..) => {
1104
+ & super :: VtableParam ( ..) => {
1088
1105
// This case tell us nothing about the value of an
1089
1106
// associated type. Consider:
1090
1107
//
@@ -1110,19 +1127,32 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
1110
1127
// in the compiler: a trait predicate (`T : SomeTrait`) and a
1111
1128
// projection. And the projection where clause is handled
1112
1129
// in `assemble_candidates_from_param_env`.
1130
+ false
1113
1131
}
1114
- super :: VtableAutoImpl ( ..) |
1115
- super :: VtableBuiltin ( ..) => {
1132
+ & super :: VtableAutoImpl ( ..) |
1133
+ & super :: VtableBuiltin ( ..) => {
1116
1134
// These traits have no associated types.
1117
1135
span_bug ! (
1118
1136
obligation. cause. span,
1119
1137
"Cannot project an associated type from `{:?}`" ,
1120
1138
vtable) ;
1121
1139
}
1140
+ } ;
1141
+
1142
+ if eligible {
1143
+ candidate_set. vec . push ( ProjectionTyCandidate :: Select ( vtable) ) ;
1122
1144
}
1123
1145
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
+ }
1126
1156
}
1127
1157
1128
1158
fn confirm_candidate < ' cx , ' gcx , ' tcx > (
@@ -1142,30 +1172,19 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>(
1142
1172
confirm_param_env_candidate ( selcx, obligation, poly_projection)
1143
1173
}
1144
1174
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 )
1147
1177
}
1148
1178
}
1149
1179
}
1150
1180
1151
1181
fn confirm_select_candidate < ' cx , ' gcx , ' tcx > (
1152
1182
selcx : & mut SelectionContext < ' cx , ' gcx , ' tcx > ,
1153
1183
obligation : & ProjectionTyObligation < ' tcx > ,
1154
- obligation_trait_ref : & ty:: TraitRef < ' tcx > )
1184
+ obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
1185
+ vtable : Selection < ' tcx > )
1155
1186
-> Progress < ' tcx >
1156
1187
{
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
-
1169
1188
match vtable {
1170
1189
super :: VtableImpl ( data) =>
1171
1190
confirm_impl_candidate ( selcx, obligation, data) ,
0 commit comments