@@ -4,15 +4,17 @@ use rustc_hir::def::{DefKind, Res};
44use rustc_hir:: intravisit;
55use rustc_hir:: { GenericParamKind , ImplItemKind , TraitItemKind } ;
66use rustc_infer:: infer:: { self , InferOk , TyCtxtInferExt } ;
7+ use rustc_middle:: ty;
78use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
8- use rustc_middle:: ty:: subst:: { InternalSubsts , Subst } ;
9+ use rustc_middle:: ty:: subst:: { InternalSubsts , Subst , SubstsRef } ;
910use rustc_middle:: ty:: util:: ExplicitSelf ;
10- use rustc_middle:: ty:: { self , GenericParamDefKind , TyCtxt } ;
11+ use rustc_middle:: ty:: { GenericParamDefKind , ToPredicate , TyCtxt , WithConstness } ;
1112use rustc_span:: Span ;
1213use rustc_trait_selection:: traits:: error_reporting:: InferCtxtExt ;
1314use rustc_trait_selection:: traits:: { self , ObligationCause , ObligationCauseCode , Reveal } ;
1415
1516use super :: { potentially_plural_count, FnCtxt , Inherited } ;
17+ use std:: iter;
1618
1719/// Checks that a method from an impl conforms to the signature of
1820/// the same method as declared in the trait.
@@ -1053,13 +1055,15 @@ crate fn compare_ty_impl<'tcx>(
10531055 let _: Result < ( ) , ErrorReported > = ( || {
10541056 compare_number_of_generics ( tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span) ?;
10551057
1056- compare_type_predicate_entailment ( tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref)
1058+ compare_type_predicate_entailment ( tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref) ?;
1059+
1060+ compare_projection_bounds ( tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
10571061 } ) ( ) ;
10581062}
10591063
10601064/// The equivalent of [compare_predicate_entailment], but for associated types
10611065/// instead of associated functions.
1062- fn compare_type_predicate_entailment (
1066+ fn compare_type_predicate_entailment < ' tcx > (
10631067 tcx : TyCtxt < ' tcx > ,
10641068 impl_ty : & ty:: AssocItem ,
10651069 impl_ty_span : Span ,
@@ -1161,6 +1165,152 @@ fn compare_type_predicate_entailment(
11611165 } )
11621166}
11631167
1168+ /// Validate that `ProjectionCandidate`s created for this associated type will
1169+ /// be valid.
1170+ ///
1171+ /// Usually given
1172+ ///
1173+ /// trait X { type Y: Copy } impl X for T { type Y = S; }
1174+ ///
1175+ /// We are able to normalize `<T as X>::U` to `S`, and so when we check the
1176+ /// impl is well-formed we have to prove `S: Copy`.
1177+ ///
1178+ /// For default associated types the normalization is not possible (the value
1179+ /// from the impl could be overridden). We also can't normalize generic
1180+ /// associated types (yet) because they contain bound parameters.
1181+ fn compare_projection_bounds < ' tcx > (
1182+ tcx : TyCtxt < ' tcx > ,
1183+ trait_ty : & ty:: AssocItem ,
1184+ impl_ty : & ty:: AssocItem ,
1185+ impl_ty_span : Span ,
1186+ impl_trait_ref : ty:: TraitRef < ' tcx > ,
1187+ ) -> Result < ( ) , ErrorReported > {
1188+ let is_gat = !tcx. generics_of ( impl_ty. def_id ) . params . is_empty ( ) ;
1189+ if impl_ty. defaultness . is_final ( ) && !is_gat {
1190+ // For "final", non-generic associate type implementations, we
1191+ // don't need this as described above.
1192+ return Ok ( ( ) ) ;
1193+ }
1194+
1195+ let param_env = tcx. param_env ( impl_ty. def_id ) ;
1196+
1197+ let impl_substs = InternalSubsts :: identity_for_item ( tcx, impl_ty. container . id ( ) ) ;
1198+ let impl_ty_value = tcx. type_of ( impl_ty. def_id ) ;
1199+
1200+ // Map the predicate from the trait to the corresponding one for the impl.
1201+ // For example:
1202+ //
1203+ // trait X<A> { type Y<'a>: PartialEq<A> } impl X for T { type Y<'a> = &'a S; }
1204+ // impl<'x> X<&'x u32> for () { type Y<'c> = &'c u32; }
1205+ //
1206+ // For the `for<'a> <<Self as X<A>>::Y<'a>: PartialEq<A>` bound, this
1207+ // function would translate and partially normalize
1208+ // `[<Self as X<A>>::Y<'a>, A]` to `[&'a u32, &'x u32]`.
1209+ let translate_predicate_substs = move |predicate_substs : SubstsRef < ' tcx > | {
1210+ let normalized_self = if !is_gat {
1211+ // projection_predicates only includes projections where the
1212+ // substs of the trait ref are exactly the trait's identity
1213+ // substs, so we can simply return the value from the impl.
1214+ impl_ty_value
1215+ } else {
1216+ let predicate_self_ty = predicate_substs. type_at ( 0 ) ;
1217+ let impl_ty_substs = if let ty:: Projection ( p) = predicate_self_ty. kind {
1218+ assert ! (
1219+ p. item_def_id == trait_ty. def_id,
1220+ "projection_predicates returned predicate for the wrong type: {}" ,
1221+ predicate_self_ty,
1222+ ) ;
1223+ p. substs . rebase_onto ( tcx, impl_trait_ref. def_id , impl_substs)
1224+ } else {
1225+ bug ! (
1226+ "projection_predicates returned predicate for the wrong type `{}`" ,
1227+ predicate_self_ty,
1228+ ) ;
1229+ } ;
1230+ impl_ty_value. subst ( tcx, impl_ty_substs)
1231+ } ;
1232+
1233+ tcx. mk_substs (
1234+ iter:: once ( normalized_self. into ( ) )
1235+ . chain ( predicate_substs[ 1 ..] . iter ( ) . map ( |s| s. subst ( tcx, impl_trait_ref. substs ) ) ) ,
1236+ )
1237+ } ;
1238+
1239+ tcx. infer_ctxt ( ) . enter ( move |infcx| {
1240+ let inh = Inherited :: new ( infcx, impl_ty. def_id . expect_local ( ) ) ;
1241+ let infcx = & inh. infcx ;
1242+ let mut selcx = traits:: SelectionContext :: new ( & infcx) ;
1243+
1244+ let impl_ty_hir_id = tcx. hir ( ) . as_local_hir_id ( impl_ty. def_id . expect_local ( ) ) ;
1245+ let normalize_cause = traits:: ObligationCause :: misc ( impl_ty_span, impl_ty_hir_id) ;
1246+ let cause = ObligationCause {
1247+ span : impl_ty_span,
1248+ body_id : impl_ty_hir_id,
1249+ code : ObligationCauseCode :: ItemObligation ( impl_trait_ref. def_id ) ,
1250+ } ;
1251+
1252+ let predicates = tcx. projection_predicates ( trait_ty. def_id ) ;
1253+
1254+ debug ! ( "compare_projection_bounds: projection_predicates={:?}" , predicates) ;
1255+
1256+ for predicate in predicates {
1257+ let concrete_ty_predicate = match predicate. kind ( ) {
1258+ ty:: PredicateKind :: Trait ( poly_tr, c) => poly_tr
1259+ . map_bound ( |tr| {
1260+ let trait_substs = translate_predicate_substs ( tr. trait_ref . substs ) ;
1261+ ty:: TraitRef { def_id : tr. def_id ( ) , substs : trait_substs }
1262+ } )
1263+ . with_constness ( * c)
1264+ . to_predicate ( tcx) ,
1265+ ty:: PredicateKind :: Projection ( poly_projection) => poly_projection
1266+ . map_bound ( |projection| {
1267+ let projection_substs =
1268+ translate_predicate_substs ( projection. projection_ty . substs ) ;
1269+ ty:: ProjectionPredicate {
1270+ projection_ty : ty:: ProjectionTy {
1271+ substs : projection_substs,
1272+ item_def_id : projection. projection_ty . item_def_id ,
1273+ } ,
1274+ ty : projection. ty . subst ( tcx, impl_trait_ref. substs ) ,
1275+ }
1276+ } )
1277+ . to_predicate ( tcx) ,
1278+ _ => bug ! ( "unexepected projection predicate kind: `{:?}`" , predicate) ,
1279+ } ;
1280+
1281+ let traits:: Normalized { value : normalized_predicate, obligations } = traits:: normalize (
1282+ & mut selcx,
1283+ param_env,
1284+ normalize_cause. clone ( ) ,
1285+ & concrete_ty_predicate,
1286+ ) ;
1287+
1288+ debug ! ( "compare_projection_bounds: normalized predicate = {:?}" , normalized_predicate) ;
1289+
1290+ inh. register_predicates ( obligations) ;
1291+ inh. register_predicate ( traits:: Obligation :: new (
1292+ cause. clone ( ) ,
1293+ param_env,
1294+ normalized_predicate,
1295+ ) ) ;
1296+ }
1297+
1298+ // Check that all obligations are satisfied by the implementation's
1299+ // version.
1300+ if let Err ( ref errors) = inh. fulfillment_cx . borrow_mut ( ) . select_all_or_error ( & infcx) {
1301+ infcx. report_fulfillment_errors ( errors, None , false ) ;
1302+ return Err ( ErrorReported ) ;
1303+ }
1304+
1305+ // Finally, resolve all regions. This catches wily misuses of
1306+ // lifetime parameters.
1307+ let fcx = FnCtxt :: new ( & inh, param_env, impl_ty_hir_id) ;
1308+ fcx. regionck_item ( impl_ty_hir_id, impl_ty_span, & [ ] ) ;
1309+
1310+ Ok ( ( ) )
1311+ } )
1312+ }
1313+
11641314fn assoc_item_kind_str ( impl_item : & ty:: AssocItem ) -> & ' static str {
11651315 match impl_item. kind {
11661316 ty:: AssocKind :: Const => "const" ,
0 commit comments