11//! Code for projecting associated types out of trait references.
22
3- use super :: elaborate_predicates;
43use super :: specialization_graph;
54use super :: translate_substs;
65use super :: util;
@@ -53,13 +52,16 @@ pub enum ProjectionTyError<'tcx> {
5352
5453#[ derive( PartialEq , Eq , Debug ) ]
5554enum ProjectionTyCandidate < ' tcx > {
56- // from a where-clause in the env or object type
55+ /// From a where-clause in the env or object type
5756 ParamEnv ( ty:: PolyProjectionPredicate < ' tcx > ) ,
5857
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
6059 TraitDef ( ty:: PolyProjectionPredicate < ' tcx > ) ,
6160
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)
6365 Select ( Selection < ' tcx > ) ,
6466}
6567
@@ -561,14 +563,6 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
561563 } else {
562564 obligations. extend ( ty. obligations ) ;
563565 }
564-
565- obligations. push ( get_paranoid_cache_value_obligation (
566- infcx,
567- param_env,
568- projection_ty,
569- cause,
570- depth,
571- ) ) ;
572566 return Ok ( Some ( ty. value ) ) ;
573567 }
574568 Err ( ProjectionCacheEntry :: Error ) => {
@@ -703,45 +697,6 @@ fn prune_cache_value_obligations<'a, 'tcx>(
703697 NormalizedTy { value : result. value , obligations }
704698}
705699
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-
745700/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
746701/// hold. In various error cases, we cannot generate a valid
747702/// normalized projection. Therefore, we create an inference variable
@@ -848,12 +803,21 @@ fn project_type<'cx, 'tcx>(
848803
849804 assemble_candidates_from_trait_def ( selcx, obligation, & obligation_trait_ref, & mut candidates) ;
850805
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+ } ;
852816
853817 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+ }
857821 ProjectionTyCandidateSet :: None => Ok ( ProjectedTy :: NoProgress (
858822 selcx
859823 . tcx ( )
@@ -932,6 +896,53 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
932896 )
933897}
934898
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+
935946fn assemble_candidates_from_predicates < ' cx , ' tcx > (
936947 selcx : & mut SelectionContext < ' cx , ' tcx > ,
937948 obligation : & ProjectionTyObligation < ' tcx > ,
@@ -1000,7 +1011,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
10001011 super :: ImplSource :: Closure ( _)
10011012 | super :: ImplSource :: Generator ( _)
10021013 | super :: ImplSource :: FnPointer ( _)
1003- | super :: ImplSource :: Object ( _)
10041014 | super :: ImplSource :: TraitAlias ( _) => {
10051015 debug ! ( "assemble_candidates_from_impls: impl_source={:?}" , impl_source) ;
10061016 true
@@ -1125,6 +1135,12 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
11251135 // in `assemble_candidates_from_param_env`.
11261136 false
11271137 }
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+ }
11281144 super :: ImplSource :: AutoImpl ( ..) | super :: ImplSource :: Builtin ( ..) => {
11291145 // These traits have no associated types.
11301146 selcx. tcx ( ) . sess . delay_span_bug (
@@ -1150,13 +1166,13 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
11501166fn confirm_candidate < ' cx , ' tcx > (
11511167 selcx : & mut SelectionContext < ' cx , ' tcx > ,
11521168 obligation : & ProjectionTyObligation < ' tcx > ,
1153- obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
11541169 candidate : ProjectionTyCandidate < ' tcx > ,
11551170) -> Progress < ' tcx > {
11561171 debug ! ( "confirm_candidate(candidate={:?}, obligation={:?})" , candidate, obligation) ;
11571172
11581173 let mut progress = match candidate {
1159- ProjectionTyCandidate :: ParamEnv ( poly_projection) => {
1174+ ProjectionTyCandidate :: ParamEnv ( poly_projection)
1175+ | ProjectionTyCandidate :: Object ( poly_projection) => {
11601176 confirm_param_env_candidate ( selcx, obligation, poly_projection, false )
11611177 }
11621178
@@ -1165,7 +1181,7 @@ fn confirm_candidate<'cx, 'tcx>(
11651181 }
11661182
11671183 ProjectionTyCandidate :: Select ( impl_source) => {
1168- confirm_select_candidate ( selcx, obligation, obligation_trait_ref , impl_source)
1184+ confirm_select_candidate ( selcx, obligation, impl_source)
11691185 }
11701186 } ;
11711187 // When checking for cycle during evaluation, we compare predicates with
@@ -1182,7 +1198,6 @@ fn confirm_candidate<'cx, 'tcx>(
11821198fn confirm_select_candidate < ' cx , ' tcx > (
11831199 selcx : & mut SelectionContext < ' cx , ' tcx > ,
11841200 obligation : & ProjectionTyObligation < ' tcx > ,
1185- obligation_trait_ref : & ty:: TraitRef < ' tcx > ,
11861201 impl_source : Selection < ' tcx > ,
11871202) -> Progress < ' tcx > {
11881203 match impl_source {
@@ -1193,10 +1208,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
11931208 super :: ImplSource :: DiscriminantKind ( data) => {
11941209 confirm_discriminant_kind_candidate ( selcx, obligation, data)
11951210 }
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 ( ..)
12001213 | super :: ImplSource :: Param ( ..)
12011214 | super :: ImplSource :: Builtin ( ..)
12021215 | super :: ImplSource :: TraitAlias ( ..) =>
@@ -1211,72 +1224,6 @@ fn confirm_select_candidate<'cx, 'tcx>(
12111224 }
12121225}
12131226
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-
12801227fn confirm_generator_candidate < ' cx , ' tcx > (
12811228 selcx : & mut SelectionContext < ' cx , ' tcx > ,
12821229 obligation : & ProjectionTyObligation < ' tcx > ,
0 commit comments