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