@@ -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,12 +111,59 @@ 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
- 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
+ }
119
167
}
120
168
121
169
/// Evaluates constraints of the form:
@@ -803,11 +851,11 @@ fn project_type<'cx, 'gcx, 'tcx>(
803
851
return Ok ( ProjectedTy :: Progress ( Progress :: error ( selcx. tcx ( ) ) ) ) ;
804
852
}
805
853
806
- let mut candidates = ProjectionTyCandidateSet {
807
- vec : Vec :: new ( ) ,
808
- ambiguous : false ,
809
- } ;
854
+ let mut candidates = ProjectionTyCandidateSet :: None ;
810
855
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.
811
859
assemble_candidates_from_param_env ( selcx,
812
860
obligation,
813
861
& obligation_trait_ref,
@@ -818,57 +866,27 @@ fn project_type<'cx, 'gcx, 'tcx>(
818
866
& obligation_trait_ref,
819
867
& mut candidates) ;
820
868
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 ) ,
859
889
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 ) ) )
872
890
}
873
891
}
874
892
@@ -918,7 +936,7 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>(
918
936
ty:: TyInfer ( ty:: TyVar ( _) ) => {
919
937
// If the self-type is an inference variable, then it MAY wind up
920
938
// being a projected type, so induce an ambiguity.
921
- candidate_set. ambiguous = true ;
939
+ candidate_set. mark_ambiguous ( ) ;
922
940
return ;
923
941
}
924
942
_ => { return ; }
@@ -952,7 +970,7 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
952
970
debug ! ( "assemble_candidates_from_predicates: predicate={:?}" ,
953
971
predicate) ;
954
972
match predicate {
955
- ty:: Predicate :: Projection ( ref data) => {
973
+ ty:: Predicate :: Projection ( data) => {
956
974
let same_def_id =
957
975
data. 0 . projection_ty . item_def_id == obligation. predicate . item_def_id ;
958
976
@@ -975,10 +993,10 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
975
993
data, is_match, same_def_id) ;
976
994
977
995
if is_match {
978
- candidate_set. vec . push ( ctor ( data. clone ( ) ) ) ;
996
+ candidate_set. push_candidate ( ctor ( data) ) ;
979
997
}
980
998
}
981
- _ => { }
999
+ _ => { }
982
1000
}
983
1001
}
984
1002
}
@@ -988,37 +1006,36 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
988
1006
obligation : & ProjectionTyObligation < ' tcx > ,
989
1007
obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
990
1008
candidate_set : & mut ProjectionTyCandidateSet < ' tcx > )
991
- -> Result < ( ) , SelectionError < ' tcx > >
992
1009
{
993
1010
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
994
1011
// start out by selecting the predicate `T as TraitRef<...>`:
995
1012
let poly_trait_ref = obligation_trait_ref. to_poly_trait_ref ( ) ;
996
1013
let trait_obligation = obligation. with ( poly_trait_ref. to_poly_trait_predicate ( ) ) ;
997
- selcx. infcx ( ) . probe ( |_| {
1014
+ let _ = selcx. infcx ( ) . commit_if_ok ( |_| {
998
1015
let vtable = match selcx. select ( & trait_obligation) {
999
1016
Ok ( Some ( vtable) ) => vtable,
1000
1017
Ok ( None ) => {
1001
- candidate_set. ambiguous = true ;
1002
- return Ok ( ( ) ) ;
1018
+ candidate_set. mark_ambiguous ( ) ;
1019
+ return Err ( ( ) ) ;
1003
1020
}
1004
1021
Err ( e) => {
1005
1022
debug ! ( "assemble_candidates_from_impls: selection error {:?}" ,
1006
1023
e) ;
1007
- return Err ( e) ;
1024
+ candidate_set. mark_error ( e) ;
1025
+ return Err ( ( ) ) ;
1008
1026
}
1009
1027
} ;
1010
1028
1011
- match vtable {
1029
+ let eligible = match & vtable {
1012
1030
super :: VtableClosure ( _) |
1013
1031
super :: VtableGenerator ( _) |
1014
1032
super :: VtableFnPointer ( _) |
1015
1033
super :: VtableObject ( _) => {
1016
1034
debug ! ( "assemble_candidates_from_impls: vtable={:?}" ,
1017
1035
vtable) ;
1018
-
1019
- candidate_set. vec . push ( ProjectionTyCandidate :: Select ) ;
1036
+ true
1020
1037
}
1021
- super :: VtableImpl ( ref impl_data) => {
1038
+ super :: VtableImpl ( impl_data) => {
1022
1039
// We have to be careful when projecting out of an
1023
1040
// impl because of specialization. If we are not in
1024
1041
// trans (i.e., projection mode is not "any"), and the
@@ -1062,27 +1079,25 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
1062
1079
node_item. item . defaultness . has_value ( )
1063
1080
} else {
1064
1081
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 ( ) )
1066
1083
} ;
1067
1084
1068
1085
// Only reveal a specializable default if we're past type-checking
1069
1086
// and the obligations is monomorphic, otherwise passes such as
1070
1087
// transmute checking and polymorphic MIR optimizations could
1071
1088
// 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
1074
1091
} else if obligation. param_env . reveal == Reveal :: All {
1075
1092
assert ! ( !poly_trait_ref. needs_infer( ) ) ;
1076
1093
if !poly_trait_ref. needs_subst ( ) {
1077
- Some ( ProjectionTyCandidate :: Select )
1094
+ true
1078
1095
} else {
1079
- None
1096
+ false
1080
1097
}
1081
1098
} else {
1082
- None
1083
- } ;
1084
-
1085
- candidate_set. vec . extend ( new_candidate) ;
1099
+ false
1100
+ }
1086
1101
}
1087
1102
super :: VtableParam ( ..) => {
1088
1103
// This case tell us nothing about the value of an
@@ -1110,6 +1125,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
1110
1125
// in the compiler: a trait predicate (`T : SomeTrait`) and a
1111
1126
// projection. And the projection where clause is handled
1112
1127
// in `assemble_candidates_from_param_env`.
1128
+ false
1113
1129
}
1114
1130
super :: VtableAutoImpl ( ..) |
1115
1131
super :: VtableBuiltin ( ..) => {
@@ -1119,10 +1135,18 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
1119
1135
"Cannot project an associated type from `{:?}`" ,
1120
1136
vtable) ;
1121
1137
}
1122
- }
1138
+ } ;
1123
1139
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
+ } ) ;
1126
1150
}
1127
1151
1128
1152
fn confirm_candidate < ' cx , ' gcx , ' tcx > (
@@ -1142,30 +1166,19 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>(
1142
1166
confirm_param_env_candidate ( selcx, obligation, poly_projection)
1143
1167
}
1144
1168
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 )
1147
1171
}
1148
1172
}
1149
1173
}
1150
1174
1151
1175
fn confirm_select_candidate < ' cx , ' gcx , ' tcx > (
1152
1176
selcx : & mut SelectionContext < ' cx , ' gcx , ' tcx > ,
1153
1177
obligation : & ProjectionTyObligation < ' tcx > ,
1154
- obligation_trait_ref : & ty:: TraitRef < ' tcx > )
1178
+ obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
1179
+ vtable : Selection < ' tcx > )
1155
1180
-> Progress < ' tcx >
1156
1181
{
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
1182
match vtable {
1170
1183
super :: VtableImpl ( data) =>
1171
1184
confirm_impl_candidate ( selcx, obligation, data) ,
0 commit comments