@@ -425,10 +425,109 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
425425
426426 for_item ( tcx, item) . with_fcx ( |fcx, _| {
427427 check_where_clauses ( tcx, fcx, item. span , trait_def_id, None ) ;
428+ check_associated_type_defaults ( fcx, trait_def_id) ;
429+
428430 vec ! [ ]
429431 } ) ;
430432}
431433
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+
432531fn check_item_fn ( tcx : TyCtxt < ' _ > , item : & hir:: Item < ' _ > ) {
433532 for_item ( tcx, item) . with_fcx ( |fcx, tcx| {
434533 let def_id = fcx. tcx . hir ( ) . local_def_id ( item. hir_id ) ;
0 commit comments