1
1
//! Code for projecting associated types out of trait references.
2
2
3
- use super :: elaborate_predicates;
4
3
use super :: specialization_graph;
5
4
use super :: translate_substs;
6
5
use super :: util;
@@ -53,13 +52,16 @@ pub enum ProjectionTyError<'tcx> {
53
52
54
53
#[ derive( PartialEq , Eq , Debug ) ]
55
54
enum ProjectionTyCandidate < ' tcx > {
56
- // from a where-clause in the env or object type
55
+ /// From a where-clause in the env or object type
57
56
ParamEnv ( ty:: PolyProjectionPredicate < ' tcx > ) ,
58
57
59
- // from the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C
58
+ /// From the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C
60
59
TraitDef ( ty:: PolyProjectionPredicate < ' tcx > ) ,
61
60
62
- // from a "impl" (or a "pseudo-impl" returned by select)
61
+ /// Bounds specified on an object type
62
+ Object ( ty:: PolyProjectionPredicate < ' tcx > ) ,
63
+
64
+ /// From a "impl" (or a "pseudo-impl" returned by select)
63
65
Select ( Selection < ' tcx > ) ,
64
66
}
65
67
@@ -561,14 +563,6 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
561
563
} else {
562
564
obligations. extend ( ty. obligations ) ;
563
565
}
564
-
565
- obligations. push ( get_paranoid_cache_value_obligation (
566
- infcx,
567
- param_env,
568
- projection_ty,
569
- cause,
570
- depth,
571
- ) ) ;
572
566
return Ok ( Some ( ty. value ) ) ;
573
567
}
574
568
Err ( ProjectionCacheEntry :: Error ) => {
@@ -703,45 +697,6 @@ fn prune_cache_value_obligations<'a, 'tcx>(
703
697
NormalizedTy { value : result. value , obligations }
704
698
}
705
699
706
- /// Whenever we give back a cache result for a projection like `<T as
707
- /// Trait>::Item ==> X`, we *always* include the obligation to prove
708
- /// that `T: Trait` (we may also include some other obligations). This
709
- /// may or may not be necessary -- in principle, all the obligations
710
- /// that must be proven to show that `T: Trait` were also returned
711
- /// when the cache was first populated. But there are some vague concerns,
712
- /// and so we take the precautionary measure of including `T: Trait` in
713
- /// the result:
714
- ///
715
- /// Concern #1. The current setup is fragile. Perhaps someone could
716
- /// have failed to prove the concerns from when the cache was
717
- /// populated, but also not have used a snapshot, in which case the
718
- /// cache could remain populated even though `T: Trait` has not been
719
- /// shown. In this case, the "other code" is at fault -- when you
720
- /// project something, you are supposed to either have a snapshot or
721
- /// else prove all the resulting obligations -- but it's still easy to
722
- /// get wrong.
723
- ///
724
- /// Concern #2. Even within the snapshot, if those original
725
- /// obligations are not yet proven, then we are able to do projections
726
- /// that may yet turn out to be wrong. This *may* lead to some sort
727
- /// of trouble, though we don't have a concrete example of how that
728
- /// can occur yet. But it seems risky at best.
729
- fn get_paranoid_cache_value_obligation < ' a , ' tcx > (
730
- infcx : & ' a InferCtxt < ' a , ' tcx > ,
731
- param_env : ty:: ParamEnv < ' tcx > ,
732
- projection_ty : ty:: ProjectionTy < ' tcx > ,
733
- cause : ObligationCause < ' tcx > ,
734
- depth : usize ,
735
- ) -> PredicateObligation < ' tcx > {
736
- let trait_ref = projection_ty. trait_ref ( infcx. tcx ) . to_poly_trait_ref ( ) ;
737
- Obligation {
738
- cause,
739
- recursion_depth : depth,
740
- param_env,
741
- predicate : trait_ref. without_const ( ) . to_predicate ( infcx. tcx ) ,
742
- }
743
- }
744
-
745
700
/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
746
701
/// hold. In various error cases, we cannot generate a valid
747
702
/// normalized projection. Therefore, we create an inference variable
@@ -848,12 +803,21 @@ fn project_type<'cx, 'tcx>(
848
803
849
804
assemble_candidates_from_trait_def ( selcx, obligation, & obligation_trait_ref, & mut candidates) ;
850
805
851
- assemble_candidates_from_impls ( selcx, obligation, & obligation_trait_ref, & mut candidates) ;
806
+ assemble_candidates_from_object_ty ( selcx, obligation, & obligation_trait_ref, & mut candidates) ;
807
+
808
+ if let ProjectionTyCandidateSet :: Single ( ProjectionTyCandidate :: Object ( _) ) = candidates {
809
+ // Avoid normalization cycle from selection (see
810
+ // `assemble_candidates_from_object_ty`).
811
+ // FIXME(lazy_normalization): Lazy normalization should save us from
812
+ // having to do special case this.
813
+ } else {
814
+ assemble_candidates_from_impls ( selcx, obligation, & obligation_trait_ref, & mut candidates) ;
815
+ } ;
852
816
853
817
match candidates {
854
- ProjectionTyCandidateSet :: Single ( candidate) => Ok ( ProjectedTy :: Progress (
855
- confirm_candidate ( selcx, obligation, & obligation_trait_ref , candidate) ,
856
- ) ) ,
818
+ ProjectionTyCandidateSet :: Single ( candidate) => {
819
+ Ok ( ProjectedTy :: Progress ( confirm_candidate ( selcx, obligation, candidate) ) )
820
+ }
857
821
ProjectionTyCandidateSet :: None => Ok ( ProjectedTy :: NoProgress (
858
822
selcx
859
823
. tcx ( )
@@ -932,6 +896,53 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
932
896
)
933
897
}
934
898
899
+ /// In the case of a trait object like
900
+ /// `<dyn Iterator<Item = ()> as Iterator>::Item` we can use the existential
901
+ /// predicate in the trait object.
902
+ ///
903
+ /// We don't go through the select candidate for these bounds to avoid cycles:
904
+ /// In the above case, `dyn Iterator<Item = ()>: Iterator` would create a
905
+ /// nested obligation of `<dyn Iterator<Item = ()> as Iterator>::Item: Sized`,
906
+ /// this then has to be normalized without having to prove
907
+ /// `dyn Iterator<Item = ()>: Iterator` again.
908
+ fn assemble_candidates_from_object_ty < ' cx , ' tcx > (
909
+ selcx : & mut SelectionContext < ' cx , ' tcx > ,
910
+ obligation : & ProjectionTyObligation < ' tcx > ,
911
+ obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
912
+ candidate_set : & mut ProjectionTyCandidateSet < ' tcx > ,
913
+ ) {
914
+ debug ! ( "assemble_candidates_from_object_ty(..)" ) ;
915
+
916
+ let tcx = selcx. tcx ( ) ;
917
+
918
+ let self_ty = obligation_trait_ref. self_ty ( ) ;
919
+ let object_ty = selcx. infcx ( ) . shallow_resolve ( self_ty) ;
920
+ let data = match object_ty. kind {
921
+ ty:: Dynamic ( ref data, ..) => data,
922
+ ty:: Infer ( ty:: TyVar ( _) ) => {
923
+ // If the self-type is an inference variable, then it MAY wind up
924
+ // being an object type, so induce an ambiguity.
925
+ candidate_set. mark_ambiguous ( ) ;
926
+ return ;
927
+ }
928
+ _ => return ,
929
+ } ;
930
+ let env_predicates = data
931
+ . projection_bounds ( )
932
+ . filter ( |bound| bound. item_def_id ( ) == obligation. predicate . item_def_id )
933
+ . map ( |p| p. with_self_ty ( tcx, object_ty) . to_predicate ( tcx) ) ;
934
+
935
+ assemble_candidates_from_predicates (
936
+ selcx,
937
+ obligation,
938
+ obligation_trait_ref,
939
+ candidate_set,
940
+ ProjectionTyCandidate :: Object ,
941
+ env_predicates,
942
+ false ,
943
+ ) ;
944
+ }
945
+
935
946
fn assemble_candidates_from_predicates < ' cx , ' tcx > (
936
947
selcx : & mut SelectionContext < ' cx , ' tcx > ,
937
948
obligation : & ProjectionTyObligation < ' tcx > ,
@@ -1000,7 +1011,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
1000
1011
super :: ImplSource :: Closure ( _)
1001
1012
| super :: ImplSource :: Generator ( _)
1002
1013
| super :: ImplSource :: FnPointer ( _)
1003
- | super :: ImplSource :: Object ( _)
1004
1014
| super :: ImplSource :: TraitAlias ( _) => {
1005
1015
debug ! ( "assemble_candidates_from_impls: impl_source={:?}" , impl_source) ;
1006
1016
true
@@ -1125,6 +1135,12 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
1125
1135
// in `assemble_candidates_from_param_env`.
1126
1136
false
1127
1137
}
1138
+ super :: ImplSource :: Object ( _) => {
1139
+ // Handled by the `Object` projection candidate. See
1140
+ // `assemble_candidates_from_object_ty` for an explanation of
1141
+ // why we special case object types.
1142
+ false
1143
+ }
1128
1144
super :: ImplSource :: AutoImpl ( ..) | super :: ImplSource :: Builtin ( ..) => {
1129
1145
// These traits have no associated types.
1130
1146
selcx. tcx ( ) . sess . delay_span_bug (
@@ -1150,13 +1166,13 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
1150
1166
fn confirm_candidate < ' cx , ' tcx > (
1151
1167
selcx : & mut SelectionContext < ' cx , ' tcx > ,
1152
1168
obligation : & ProjectionTyObligation < ' tcx > ,
1153
- obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
1154
1169
candidate : ProjectionTyCandidate < ' tcx > ,
1155
1170
) -> Progress < ' tcx > {
1156
1171
debug ! ( "confirm_candidate(candidate={:?}, obligation={:?})" , candidate, obligation) ;
1157
1172
1158
1173
let mut progress = match candidate {
1159
- ProjectionTyCandidate :: ParamEnv ( poly_projection) => {
1174
+ ProjectionTyCandidate :: ParamEnv ( poly_projection)
1175
+ | ProjectionTyCandidate :: Object ( poly_projection) => {
1160
1176
confirm_param_env_candidate ( selcx, obligation, poly_projection, false )
1161
1177
}
1162
1178
@@ -1165,7 +1181,7 @@ fn confirm_candidate<'cx, 'tcx>(
1165
1181
}
1166
1182
1167
1183
ProjectionTyCandidate :: Select ( impl_source) => {
1168
- confirm_select_candidate ( selcx, obligation, obligation_trait_ref , impl_source)
1184
+ confirm_select_candidate ( selcx, obligation, impl_source)
1169
1185
}
1170
1186
} ;
1171
1187
// When checking for cycle during evaluation, we compare predicates with
@@ -1182,7 +1198,6 @@ fn confirm_candidate<'cx, 'tcx>(
1182
1198
fn confirm_select_candidate < ' cx , ' tcx > (
1183
1199
selcx : & mut SelectionContext < ' cx , ' tcx > ,
1184
1200
obligation : & ProjectionTyObligation < ' tcx > ,
1185
- obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
1186
1201
impl_source : Selection < ' tcx > ,
1187
1202
) -> Progress < ' tcx > {
1188
1203
match impl_source {
@@ -1193,10 +1208,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
1193
1208
super :: ImplSource :: DiscriminantKind ( data) => {
1194
1209
confirm_discriminant_kind_candidate ( selcx, obligation, data)
1195
1210
}
1196
- super :: ImplSource :: Object ( _) => {
1197
- confirm_object_candidate ( selcx, obligation, obligation_trait_ref)
1198
- }
1199
- super :: ImplSource :: AutoImpl ( ..)
1211
+ super :: ImplSource :: Object ( _)
1212
+ | super :: ImplSource :: AutoImpl ( ..)
1200
1213
| super :: ImplSource :: Param ( ..)
1201
1214
| super :: ImplSource :: Builtin ( ..)
1202
1215
| super :: ImplSource :: TraitAlias ( ..) =>
@@ -1211,72 +1224,6 @@ fn confirm_select_candidate<'cx, 'tcx>(
1211
1224
}
1212
1225
}
1213
1226
1214
- fn confirm_object_candidate < ' cx , ' tcx > (
1215
- selcx : & mut SelectionContext < ' cx , ' tcx > ,
1216
- obligation : & ProjectionTyObligation < ' tcx > ,
1217
- obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
1218
- ) -> Progress < ' tcx > {
1219
- let self_ty = obligation_trait_ref. self_ty ( ) ;
1220
- let object_ty = selcx. infcx ( ) . shallow_resolve ( self_ty) ;
1221
- debug ! ( "confirm_object_candidate(object_ty={:?})" , object_ty) ;
1222
- let data = match object_ty. kind ( ) {
1223
- ty:: Dynamic ( data, ..) => data,
1224
- _ => span_bug ! (
1225
- obligation. cause. span,
1226
- "confirm_object_candidate called with non-object: {:?}" ,
1227
- object_ty
1228
- ) ,
1229
- } ;
1230
- let env_predicates = data
1231
- . projection_bounds ( )
1232
- . map ( |p| p. with_self_ty ( selcx. tcx ( ) , object_ty) . to_predicate ( selcx. tcx ( ) ) ) ;
1233
- let env_predicate = {
1234
- let env_predicates = elaborate_predicates ( selcx. tcx ( ) , env_predicates) ;
1235
-
1236
- // select only those projections that are actually projecting an
1237
- // item with the correct name
1238
-
1239
- let env_predicates = env_predicates. filter_map ( |o| match o. predicate . skip_binders ( ) {
1240
- ty:: PredicateAtom :: Projection ( data)
1241
- if data. projection_ty . item_def_id == obligation. predicate . item_def_id =>
1242
- {
1243
- Some ( ty:: Binder :: bind ( data) )
1244
- }
1245
- _ => None ,
1246
- } ) ;
1247
-
1248
- // select those with a relevant trait-ref
1249
- let mut env_predicates = env_predicates. filter ( |data| {
1250
- let data_poly_trait_ref = data. to_poly_trait_ref ( selcx. tcx ( ) ) ;
1251
- let obligation_poly_trait_ref = obligation_trait_ref. to_poly_trait_ref ( ) ;
1252
- selcx. infcx ( ) . probe ( |_| {
1253
- selcx
1254
- . infcx ( )
1255
- . at ( & obligation. cause , obligation. param_env )
1256
- . sup ( obligation_poly_trait_ref, data_poly_trait_ref)
1257
- . is_ok ( )
1258
- } )
1259
- } ) ;
1260
-
1261
- // select the first matching one; there really ought to be one or
1262
- // else the object type is not WF, since an object type should
1263
- // include all of its projections explicitly
1264
- match env_predicates. next ( ) {
1265
- Some ( env_predicate) => env_predicate,
1266
- None => {
1267
- debug ! (
1268
- "confirm_object_candidate: no env-predicate \
1269
- found in object type `{:?}`; ill-formed",
1270
- object_ty
1271
- ) ;
1272
- return Progress :: error ( selcx. tcx ( ) ) ;
1273
- }
1274
- }
1275
- } ;
1276
-
1277
- confirm_param_env_candidate ( selcx, obligation, env_predicate, false )
1278
- }
1279
-
1280
1227
fn confirm_generator_candidate < ' cx , ' tcx > (
1281
1228
selcx : & mut SelectionContext < ' cx , ' tcx > ,
1282
1229
obligation : & ProjectionTyObligation < ' tcx > ,
0 commit comments