@@ -1713,24 +1713,60 @@ fn check_specialization_validity<'tcx>(
17131713 impl_id : DefId ,
17141714 impl_item : & hir:: ImplItem ,
17151715) {
1716- let ancestors = trait_def. ancestors ( tcx, impl_id) ;
1717-
17181716 let kind = match impl_item. kind {
17191717 hir:: ImplItemKind :: Const ( ..) => ty:: AssocKind :: Const ,
17201718 hir:: ImplItemKind :: Method ( ..) => ty:: AssocKind :: Method ,
17211719 hir:: ImplItemKind :: OpaqueTy ( ..) => ty:: AssocKind :: OpaqueTy ,
17221720 hir:: ImplItemKind :: TyAlias ( _) => ty:: AssocKind :: Type ,
17231721 } ;
17241722
1725- let parent = ancestors. defs ( tcx, trait_item. ident , kind, trait_def. def_id ) . nth ( 1 )
1726- . map ( |node_item| node_item. map ( |parent| parent. defaultness ) ) ;
1723+ let mut ancestor_impls = trait_def. ancestors ( tcx, impl_id)
1724+ . skip ( 1 )
1725+ . filter_map ( |parent| {
1726+ if parent. is_from_trait ( ) {
1727+ None
1728+ } else {
1729+ Some ( ( parent, parent. item ( tcx, trait_item. ident , kind, trait_def. def_id ) ) )
1730+ }
1731+ } )
1732+ . peekable ( ) ;
17271733
1728- if let Some ( parent) = parent {
1729- if tcx. impl_item_is_final ( & parent) {
1730- report_forbidden_specialization ( tcx, impl_item, parent. node . def_id ( ) ) ;
1731- }
1734+ if ancestor_impls. peek ( ) . is_none ( ) {
1735+ // No parent, nothing to specialize.
1736+ return ;
17321737 }
17331738
1739+ let opt_result = ancestor_impls. find_map ( |( parent_impl, parent_item) | {
1740+ match parent_item {
1741+ // Parent impl exists, and contains the parent item we're trying to specialize, but
1742+ // doesn't mark it `default`.
1743+ Some ( parent_item) if tcx. impl_item_is_final ( & parent_item) => {
1744+ Some ( Err ( parent_impl. def_id ( ) ) )
1745+ }
1746+
1747+ // Parent impl contains item and makes it specializable.
1748+ Some ( _) => {
1749+ Some ( Ok ( ( ) ) )
1750+ }
1751+
1752+ // Parent impl doesn't mention the item. This means it's inherited from the
1753+ // grandparent. In that case, if parent is a `default impl`, inherited items use the
1754+ // "defaultness" from the grandparent, else they are final.
1755+ None => if tcx. impl_is_default ( parent_impl. def_id ( ) ) {
1756+ None
1757+ } else {
1758+ Some ( Err ( parent_impl. def_id ( ) ) )
1759+ }
1760+ }
1761+ } ) ;
1762+
1763+ // If `opt_result` is `None`, we have only encoutered `default impl`s that don't contain the
1764+ // item. This is allowed, the item isn't actually getting specialized here.
1765+ let result = opt_result. unwrap_or ( Ok ( ( ) ) ) ;
1766+
1767+ if let Err ( parent_impl) = result {
1768+ report_forbidden_specialization ( tcx, impl_item, parent_impl) ;
1769+ }
17341770}
17351771
17361772fn check_impl_items_against_trait < ' tcx > (
@@ -1846,8 +1882,7 @@ fn check_impl_items_against_trait<'tcx>(
18461882 let associated_type_overridden = overridden_associated_type. is_some ( ) ;
18471883 for trait_item in tcx. associated_items ( impl_trait_ref. def_id ) {
18481884 let is_implemented = trait_def. ancestors ( tcx, impl_id)
1849- . defs ( tcx, trait_item. ident , trait_item. kind , impl_trait_ref. def_id )
1850- . next ( )
1885+ . leaf_def ( tcx, trait_item. ident , trait_item. kind )
18511886 . map ( |node_item| !node_item. node . is_from_trait ( ) )
18521887 . unwrap_or ( false ) ;
18531888
0 commit comments