@@ -287,6 +287,67 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
287287 keep_items
288288 }
289289
290+ // First, remove and store `impl` items, indexing them by the type they belong to.
291+ let mut impls: HashMap < DefId , MovedDeclImpl > = HashMap :: new ( ) ;
292+ FlatMapNodes :: visit ( krate, |mut item : P < Item > | {
293+ if let Some ( ( path, _) ) = parse_source_header ( & item. attrs ) {
294+ let header_item = item. clone ( ) ;
295+ if let ItemKind :: Mod ( _, ModKind :: Loaded ( ref mut mod_items, _, _) ) = & mut item. kind {
296+ mod_items. retain ( |item| {
297+ if let ItemKind :: Impl ( impl_) = & item. kind {
298+ // Only keep `impl` items with simple path types, and only if they
299+ // contain nothing but `const` items.
300+ fn impl_type_def_id ( cx : & RefactorCtxt , impl_ : & Impl ) -> Option < DefId > {
301+ // Only inherent `impl`s that contain no items other than `const`.
302+ if impl_. of_trait . is_some ( )
303+ || !impl_
304+ . items
305+ . iter ( )
306+ . all ( |item| matches ! ( item. kind, AssocItemKind :: Const ( ..) ) )
307+ {
308+ return None ;
309+ } ;
310+ let ty = match cx. hir_map ( ) . find ( impl_. self_ty . id ) ? {
311+ hir:: Node :: Ty ( ty) => ty,
312+ _ => return None ,
313+ } ;
314+ let ty_path = match & ty. kind {
315+ hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None , path) ) => path,
316+ _ => return None ,
317+ } ;
318+ match ty_path. res {
319+ Res :: Def ( _, def_id) => Some ( def_id) ,
320+ _ => None ,
321+ }
322+ }
323+
324+ if let Some ( impl_type_def_id) = impl_type_def_id ( & self . cx , & impl_) {
325+ impls. entry ( impl_type_def_id) . or_insert_with ( || {
326+ let parent_header =
327+ HeaderInfo :: new ( header_item. ident , path. clone ( ) ) ;
328+ MovedDeclImpl {
329+ item : item. clone ( ) ,
330+ parent_header,
331+ }
332+ } ) ;
333+ }
334+
335+ false
336+ } else {
337+ true
338+ }
339+ } ) ;
340+
341+ smallvec ! [ item]
342+ } else {
343+ panic ! ( "Unexpected Item kind with header_src attribute" ) ;
344+ }
345+ } else {
346+ smallvec ! [ item]
347+ }
348+ } ) ;
349+
350+ // Process all the remaining items.
290351 let mut declarations = HeaderDeclarations :: new ( self . cx ) ;
291352 FlatMapNodes :: visit ( krate, |mut item : P < Item > | {
292353 if let Some ( ( path, _) ) = parse_source_header ( & item. attrs ) {
@@ -321,8 +382,13 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
321382 }
322383 }
323384
385+ let new_def_id = self . cx . node_def_id ( item. id ) ;
324386 let header_info = HeaderInfo :: new ( header_item. ident , path. clone ( ) ) ;
325- let inserted = declarations. insert_item ( item. clone ( ) , header_info) ;
387+ let inserted = declarations. insert_item (
388+ item. clone ( ) ,
389+ header_info,
390+ impls. remove ( & new_def_id) ,
391+ ) ;
326392 // Keep the item if we are not collapsing it
327393 !inserted
328394 } ) ;
@@ -676,7 +742,7 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
676742 } else {
677743 let namespace = self . cx . item_namespace ( & item) ;
678744 if let Some ( namespace) = namespace {
679- match declarations. find_item ( item, namespace) {
745+ match declarations. find_item ( item, namespace, None ) {
680746 ContainsDecl :: NotContained => false ,
681747 ContainsDecl :: Equivalent ( _) => true ,
682748 ContainsDecl :: Definition ( _) => true ,
@@ -750,6 +816,13 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
750816 // Remove src_loc attributes
751817 FlatMapNodes :: visit ( krate, |mut item : P < Item > | {
752818 item. attrs . retain ( |attr| !is_c2rust_attr ( attr, "src_loc" ) ) ;
819+
820+ if let ItemKind :: Impl ( impl_) = & mut item. kind {
821+ for item in & mut impl_. items {
822+ item. attrs . retain ( |attr| !is_c2rust_attr ( attr, "src_loc" ) ) ;
823+ }
824+ }
825+
753826 smallvec ! [ item]
754827 } ) ;
755828 FlatMapNodes :: visit ( krate, |mut item : P < ForeignItem > | {
@@ -1085,10 +1158,23 @@ struct MovedDecl {
10851158 namespace : Namespace ,
10861159 loc : Option < SrcLoc > ,
10871160 parent_header : HeaderInfo ,
1161+ impl_ : Option < MovedDeclImpl > ,
1162+ }
1163+
1164+ #[ derive( Debug , Clone ) ]
1165+ struct MovedDeclImpl {
1166+ item : P < Item > ,
1167+ parent_header : HeaderInfo ,
10881168}
10891169
10901170impl MovedDecl {
1091- fn new < T > ( decl : T , def_id : DefId , namespace : Namespace , parent_header : HeaderInfo ) -> Self
1171+ fn new < T > (
1172+ decl : T ,
1173+ def_id : DefId ,
1174+ namespace : Namespace ,
1175+ parent_header : HeaderInfo ,
1176+ impl_ : Option < MovedDeclImpl > ,
1177+ ) -> Self
10921178 where
10931179 T : Into < DeclKind > ,
10941180 {
@@ -1105,6 +1191,7 @@ impl MovedDecl {
11051191 namespace,
11061192 loc,
11071193 parent_header,
1194+ impl_,
11081195 }
11091196 }
11101197
@@ -1291,14 +1378,12 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
12911378
12921379 /// Add an item into the module. If it has a name conflict with an existing
12931380 /// item, choose the definition item over any declarations.
1294- pub fn insert_item ( & mut self , mut item : P < Item > , parent_header : HeaderInfo ) -> bool {
1295- let namespace = self . cx . item_namespace ( & item) ;
1296- let new_def_id = self . cx . node_def_id ( item. id ) ;
1297- let ident = if let ItemKind :: Use ( tree) = & item. kind {
1298- tree. ident ( )
1299- } else {
1300- item. ident
1301- } ;
1381+ pub fn insert_item (
1382+ & mut self ,
1383+ mut item : P < Item > ,
1384+ parent_header : HeaderInfo ,
1385+ impl_ : Option < MovedDeclImpl > ,
1386+ ) -> bool {
13021387 match & item. kind {
13031388 // We have to disambiguate anonymous items by contents,
13041389 // since we don't have a proper Ident.
@@ -1307,7 +1392,7 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
13071392 // ident_map.
13081393 ItemKind :: Use ( tree) if is_nested ( tree) => {
13091394 for u in split_uses ( item) . into_iter ( ) {
1310- self . insert_item ( u, parent_header. clone ( ) ) ;
1395+ self . insert_item ( u, parent_header. clone ( ) , impl_ . clone ( ) ) ;
13111396 }
13121397 true
13131398 }
@@ -1335,11 +1420,24 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
13351420 // we don't have any items with the same name but different
13361421 // contents.
13371422 _ => {
1423+ let namespace = self . cx . item_namespace ( & item) ;
1424+ let new_def_id = self . cx . node_def_id ( item. id ) ;
1425+ let ident = if let ItemKind :: Use ( tree) = & item. kind {
1426+ tree. ident ( )
1427+ } else {
1428+ item. ident
1429+ } ;
13381430 let unnamed = ident. as_str ( ) . contains ( "C2Rust_Unnamed" ) ;
1339- let def_id_mapping = match self . find_item ( & item, namespace. unwrap ( ) ) {
1431+ let impl_item = impl_. as_ref ( ) . map ( |impl_| & * impl_. item ) ;
1432+ let def_id_mapping = match self . find_item ( & item, namespace. unwrap ( ) , impl_item) {
13401433 ContainsDecl :: NotContained => {
1341- let new_item =
1342- MovedDecl :: new ( item, new_def_id, namespace. unwrap ( ) , parent_header) ;
1434+ let new_item = MovedDecl :: new (
1435+ item,
1436+ new_def_id,
1437+ namespace. unwrap ( ) ,
1438+ parent_header,
1439+ impl_,
1440+ ) ;
13431441 if unnamed {
13441442 self . unnamed_items [ namespace. unwrap ( ) ] . push ( new_item) ;
13451443 } else {
@@ -1359,17 +1457,27 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
13591457 ContainsDecl :: Use ( existing) => {
13601458 let existing_def_id = existing. def_id ;
13611459 existing. join_visibility ( & item. vis . kind ) ;
1362- * existing =
1363- MovedDecl :: new ( item, new_def_id, namespace. unwrap ( ) , parent_header) ;
1460+ * existing = MovedDecl :: new (
1461+ item,
1462+ new_def_id,
1463+ namespace. unwrap ( ) ,
1464+ parent_header,
1465+ impl_,
1466+ ) ;
13641467 Some ( ( existing_def_id, new_def_id) )
13651468 }
13661469
13671470 ContainsDecl :: Equivalent ( existing) if existing. is_foreign ( ) => {
13681471 let existing_def_id = existing. def_id ;
13691472 item. vis . kind =
13701473 join_visibility ( & existing. visibility ( ) . kind , & item. vis . kind ) ;
1371- * existing =
1372- MovedDecl :: new ( item, new_def_id, namespace. unwrap ( ) , parent_header) ;
1474+ * existing = MovedDecl :: new (
1475+ item,
1476+ new_def_id,
1477+ namespace. unwrap ( ) ,
1478+ parent_header,
1479+ impl_,
1480+ ) ;
13731481 Some ( ( existing_def_id, new_def_id) )
13741482 }
13751483
@@ -1395,6 +1503,7 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
13951503 new_def_id,
13961504 namespace,
13971505 parent_header. clone ( ) ,
1506+ None ,
13981507 ) ;
13991508 if unnamed {
14001509 self . unnamed_items [ namespace] . push ( new_item) ;
@@ -1414,6 +1523,7 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
14141523 new_def_id,
14151524 namespace,
14161525 parent_header. clone ( ) ,
1526+ None ,
14171527 ) ;
14181528 Some ( ( existing_def_id, new_def_id) )
14191529 }
@@ -1507,6 +1617,17 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
15071617 foreign_items. entry ( abi) . or_default ( ) . push ( fi) ;
15081618 }
15091619 }
1620+
1621+ // If there is an impl item, add it now.
1622+ if let Some ( impl_) = item. impl_ {
1623+ let cur_mod_name = impl_. parent_header . ident ;
1624+ let i = impl_. item ;
1625+ if last_item_mod != Some ( cur_mod_name) {
1626+ st. add_comment ( i. id , make_header_comment ( last_item_mod, cur_mod_name) ) ;
1627+ last_item_mod = Some ( cur_mod_name) ;
1628+ }
1629+ items. push ( i) ;
1630+ }
15101631 }
15111632
15121633 let foreign_mods = foreign_items
@@ -1516,14 +1637,30 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
15161637 foreign_mods. chain ( items. into_iter ( ) ) . collect ( )
15171638 }
15181639
1519- fn find_item < ' b > ( & ' b mut self , item : & Item , namespace : Namespace ) -> ContainsDecl < ' b > {
1640+ fn find_item < ' b > (
1641+ & ' b mut self ,
1642+ item : & Item ,
1643+ namespace : Namespace ,
1644+ impl_item : Option < & Item > ,
1645+ ) -> ContainsDecl < ' b > {
15201646 let ident = if let ItemKind :: Use ( tree) = & item. kind {
15211647 tree. ident ( )
15221648 } else {
15231649 item. ident
15241650 } ;
15251651 assert ! ( ident. name != kw:: Empty ) ;
15261652
1653+ let impl_is_compatible = |existing_decl : & MovedDecl | -> bool {
1654+ match ( impl_item, & existing_decl. impl_ ) {
1655+ ( None , None ) => true ,
1656+ ( Some ( impl_item) , Some ( existing_impl) ) => {
1657+ self . cx
1658+ . compatible_types ( impl_item, & existing_impl. item , false )
1659+ }
1660+ _ => false ,
1661+ }
1662+ } ;
1663+
15271664 if ident. as_str ( ) . contains ( "C2Rust_Unnamed" ) {
15281665 for existing_decl in self . unnamed_items [ namespace] . iter_mut ( ) {
15291666 match & existing_decl. kind {
@@ -1534,7 +1671,9 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
15341671 | ItemKind :: Enum ( ..) => {
15351672 // Does the new item match the existing item, except
15361673 // for unnamed names?
1537- if item. kind . unnamed_equiv ( & existing_item. kind ) {
1674+ if item. kind . unnamed_equiv ( & existing_item. kind )
1675+ && impl_is_compatible ( existing_decl)
1676+ {
15381677 return ContainsDecl :: Equivalent ( existing_decl) ;
15391678 }
15401679 }
@@ -1579,7 +1718,9 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
15791718 // Otherwise make sure these items are structurally
15801719 // equivalent.
15811720 _ => {
1582- if self . cx . compatible_types ( & item, & existing_item, true ) {
1721+ if self . cx . compatible_types ( & item, & existing_item, true )
1722+ && impl_is_compatible ( existing_decl)
1723+ {
15831724 return ContainsDecl :: Equivalent ( existing_decl) ;
15841725 }
15851726 }
0 commit comments