@@ -425,10 +425,109 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
425
425
426
426
for_item ( tcx, item) . with_fcx ( |fcx, _| {
427
427
check_where_clauses ( tcx, fcx, item. span , trait_def_id, None ) ;
428
+ check_associated_type_defaults ( fcx, trait_def_id) ;
429
+
428
430
vec ! [ ]
429
431
} ) ;
430
432
}
431
433
434
+ /// Checks all associated type defaults of trait `trait_def_id`.
435
+ ///
436
+ /// Assuming the defaults are used, check that all predicates (bounds on the
437
+ /// assoc type and where clauses on the trait) hold.
438
+ fn check_associated_type_defaults ( fcx : & FnCtxt < ' _ , ' _ > , trait_def_id : DefId ) {
439
+ let tcx = fcx. tcx ;
440
+ let substs = InternalSubsts :: identity_for_item ( tcx, trait_def_id) ;
441
+
442
+ // For all assoc. types with defaults, build a map from
443
+ // `<Self as Trait<...>>::Assoc` to the default type.
444
+ let map = tcx
445
+ . associated_items ( trait_def_id)
446
+ . in_definition_order ( )
447
+ . filter_map ( |item| {
448
+ if item. kind == ty:: AssocKind :: Type && item. defaultness . has_value ( ) {
449
+ // `<Self as Trait<...>>::Assoc`
450
+ let proj = ty:: ProjectionTy { substs, item_def_id : item. def_id } ;
451
+ let default_ty = tcx. type_of ( item. def_id ) ;
452
+ debug ! ( "assoc. type default mapping: {} -> {}" , proj, default_ty) ;
453
+ Some ( ( proj, default_ty) )
454
+ } else {
455
+ None
456
+ }
457
+ } )
458
+ . collect :: < FxHashMap < _ , _ > > ( ) ;
459
+
460
+ /// Replaces projections of associated types with their default types.
461
+ ///
462
+ /// This does a "shallow substitution", meaning that defaults that refer to
463
+ /// other defaulted assoc. types will still refer to the projection
464
+ /// afterwards, not to the other default. For example:
465
+ ///
466
+ /// ```compile_fail
467
+ /// trait Tr {
468
+ /// type A: Clone = Vec<Self::B>;
469
+ /// type B = u8;
470
+ /// }
471
+ /// ```
472
+ ///
473
+ /// This will end up replacing the bound `Self::A: Clone` with
474
+ /// `Vec<Self::B>: Clone`, not with `Vec<u8>: Clone`. If we did a deep
475
+ /// substitution and ended up with the latter, the trait would be accepted.
476
+ /// If an `impl` then replaced `B` with something that isn't `Clone`,
477
+ /// suddenly the default for `A` is no longer valid. The shallow
478
+ /// substitution forces the trait to add a `B: Clone` bound to be accepted,
479
+ /// which means that an `impl` can replace any default without breaking
480
+ /// others.
481
+ ///
482
+ /// Note that this isn't needed for soundness: The defaults would still be
483
+ /// checked in any impl that doesn't override them.
484
+ struct DefaultNormalizer < ' tcx > {
485
+ tcx : TyCtxt < ' tcx > ,
486
+ map : FxHashMap < ty:: ProjectionTy < ' tcx > , Ty < ' tcx > > ,
487
+ }
488
+
489
+ impl < ' tcx > ty:: fold:: TypeFolder < ' tcx > for DefaultNormalizer < ' tcx > {
490
+ fn tcx < ' a > ( & ' a self ) -> TyCtxt < ' tcx > {
491
+ self . tcx
492
+ }
493
+
494
+ fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
495
+ match t. kind {
496
+ ty:: Projection ( proj_ty) => {
497
+ if let Some ( default) = self . map . get ( & proj_ty) {
498
+ default
499
+ } else {
500
+ t. super_fold_with ( self )
501
+ }
502
+ }
503
+ _ => t. super_fold_with ( self ) ,
504
+ }
505
+ }
506
+ }
507
+
508
+ // Now take all predicates defined on the trait, replace any mention of
509
+ // the assoc. types with their default, and prove them.
510
+ // We only consider predicates that directly mention the assoc. type.
511
+ let mut norm = DefaultNormalizer { tcx, map } ;
512
+ let predicates = fcx. tcx . predicates_of ( trait_def_id) ;
513
+ for & ( orig_pred, span) in predicates. predicates . iter ( ) {
514
+ let pred = orig_pred. fold_with ( & mut norm) ;
515
+ if pred != orig_pred {
516
+ // Mentions one of the defaulted assoc. types
517
+ debug ! ( "default suitability check: proving predicate: {} -> {}" , orig_pred, pred) ;
518
+ let pred = fcx. normalize_associated_types_in ( span, & pred) ;
519
+ let cause = traits:: ObligationCause :: new (
520
+ span,
521
+ fcx. body_id ,
522
+ traits:: ItemObligation ( trait_def_id) ,
523
+ ) ;
524
+ let obligation = traits:: Obligation :: new ( cause, fcx. param_env , pred) ;
525
+
526
+ fcx. register_predicate ( obligation) ;
527
+ }
528
+ }
529
+ }
530
+
432
531
fn check_item_fn ( tcx : TyCtxt < ' _ > , item : & hir:: Item < ' _ > ) {
433
532
for_item ( tcx, item) . with_fcx ( |fcx, tcx| {
434
533
let def_id = fcx. tcx . hir ( ) . local_def_id ( item. hir_id ) ;
0 commit comments