Skip to content

Commit 43e8bfe

Browse files
committed
test
1 parent fe1a026 commit 43e8bfe

4 files changed

Lines changed: 299 additions & 25 deletions

File tree

c2rust-refactor/src/context.rs

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use std::ops::Deref;
44

55
use rustc_ast::ptr::P;
66
use rustc_ast::{
7-
Expr, ExprKind, FnDecl, FnRetTy, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId, Path,
8-
QSelf, UseTreeKind, DUMMY_NODE_ID,
7+
AssocItem, Expr, ExprKind, FnDecl, FnRetTy, ForeignItem, ForeignItemKind, Item, ItemKind,
8+
NodeId, Path, QSelf, UseTreeKind, DUMMY_NODE_ID,
99
};
1010
use rustc_data_structures::fx::FxHashMap;
1111
use rustc_errors::{DiagnosticBuilder, Level};
@@ -1072,6 +1072,16 @@ impl<'a, 'tcx, 'b> TypeCompare<'a, 'tcx, 'b> {
10721072
pub fn compatible_types(&self, item1: &Item, item2: &Item, match_vis: bool) -> bool {
10731073
use rustc_ast::ItemKind::*;
10741074
match (&item1.kind, &item2.kind) {
1075+
(Impl(box ref impl1), Impl(box ref impl2)) => {
1076+
if impl1.items.len() != impl2.items.len() {
1077+
return false;
1078+
}
1079+
1080+
(impl1.items.iter())
1081+
.zip(impl2.items.iter())
1082+
.all(|(item1, item2)| self.compatible_assoc_items(item1, item2, match_vis))
1083+
}
1084+
10751085
// * Assure that these two items are in fact of the same type, just to be safe.
10761086
(TyAlias(box ref ta1), TyAlias(box ref ta2)) => {
10771087
match (
@@ -1226,6 +1236,40 @@ impl<'a, 'tcx, 'b> TypeCompare<'a, 'tcx, 'b> {
12261236
}
12271237
}
12281238

1239+
pub fn compatible_assoc_items(
1240+
&self,
1241+
item1: &AssocItem,
1242+
item2: &AssocItem,
1243+
match_vis: bool,
1244+
) -> bool {
1245+
use rustc_ast::AssocItemKind::*;
1246+
1247+
// Unlike for regular items, associated items must also match by name.
1248+
if item1.ident.as_str() != item2.ident.as_str() {
1249+
return false;
1250+
}
1251+
1252+
match (&item1.kind, &item2.kind) {
1253+
(Const(def1, ty1, expr1), Const(def2, ty2, expr2)) => match (
1254+
self.cx.opt_node_type(item1.id),
1255+
self.cx.opt_node_type(item2.id),
1256+
) {
1257+
(Some(ty1), Some(ty2)) => {
1258+
self.structural_eq_tys(ty1, ty2)
1259+
&& expr1.unnamed_equiv(expr2)
1260+
&& def1.unnamed_equiv(def2)
1261+
}
1262+
_ => {
1263+
self.structural_eq_ast_tys(ty1, ty2, match_vis)
1264+
&& expr1.unnamed_equiv(expr2)
1265+
&& def1.unnamed_equiv(def2)
1266+
}
1267+
},
1268+
1269+
_ => false,
1270+
}
1271+
}
1272+
12291273
/// Compare two function declarations for equivalent argument and return types,
12301274
/// ignoring argument names.
12311275
pub fn compatible_fn_prototypes(&self, decl1: &FnDecl, decl2: &FnDecl) -> bool {

c2rust-refactor/src/transform/reorganize_definitions.rs

Lines changed: 164 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,67 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
288288
keep_items
289289
}
290290

291+
// First, remove and store `impl` items, indexing them by the type they belong to.
292+
let mut impls: HashMap<DefId, MovedDeclImpl> = HashMap::new();
293+
FlatMapNodes::visit(krate, |mut item: P<Item>| {
294+
if let Some((path, _)) = parse_source_header(&item.attrs) {
295+
let header_item = item.clone();
296+
if let ItemKind::Mod(_, ModKind::Loaded(ref mut mod_items, _, _)) = &mut item.kind {
297+
mod_items.retain(|item| {
298+
if let ItemKind::Impl(impl_) = &item.kind {
299+
// Only keep `impl` items with simple path types, and only if they
300+
// contain nothing but `const` items.
301+
fn impl_type_def_id(cx: &RefactorCtxt, impl_: &Impl) -> Option<DefId> {
302+
// Only inherent `impl`s that contain no items other than `const`.
303+
if impl_.of_trait.is_some()
304+
|| !impl_
305+
.items
306+
.iter()
307+
.all(|item| matches!(item.kind, AssocItemKind::Const(..)))
308+
{
309+
return None;
310+
};
311+
let ty = match cx.hir_map().find(impl_.self_ty.id)? {
312+
hir::Node::Ty(ty) => ty,
313+
_ => return None,
314+
};
315+
let ty_path = match &ty.kind {
316+
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => path,
317+
_ => return None,
318+
};
319+
match ty_path.res {
320+
Res::Def(_, def_id) => Some(def_id),
321+
_ => None,
322+
}
323+
}
324+
325+
if let Some(impl_type_def_id) = impl_type_def_id(&self.cx, &impl_) {
326+
impls.entry(impl_type_def_id).or_insert_with(|| {
327+
let parent_header =
328+
HeaderInfo::new(header_item.ident, path.clone());
329+
MovedDeclImpl {
330+
item: item.clone(),
331+
parent_header,
332+
}
333+
});
334+
}
335+
336+
false
337+
} else {
338+
true
339+
}
340+
});
341+
342+
smallvec![item]
343+
} else {
344+
panic!("Unexpected Item kind with header_src attribute");
345+
}
346+
} else {
347+
smallvec![item]
348+
}
349+
});
350+
351+
// Process all the remaining items.
291352
let mut declarations = HeaderDeclarations::new(self.cx);
292353
FlatMapNodes::visit(krate, |mut item: P<Item>| {
293354
if let Some((path, _)) = parse_source_header(&item.attrs) {
@@ -322,8 +383,13 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
322383
}
323384
}
324385

386+
let new_def_id = self.cx.node_def_id(item.id);
325387
let header_info = HeaderInfo::new(header_item.ident, path.clone());
326-
let inserted = declarations.insert_item(item.clone(), header_info);
388+
let inserted = declarations.insert_item(
389+
item.clone(),
390+
header_info,
391+
impls.remove(&new_def_id),
392+
);
327393
// Keep the item if we are not collapsing it
328394
!inserted
329395
});
@@ -677,7 +743,7 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
677743
} else {
678744
let namespace = self.cx.item_namespace(&item);
679745
if let Some(namespace) = namespace {
680-
match declarations.find_item(item, namespace) {
746+
match declarations.find_item(item, namespace, None) {
681747
ContainsDecl::NotContained => false,
682748
ContainsDecl::Equivalent(_) => true,
683749
ContainsDecl::Definition(_) => true,
@@ -751,6 +817,13 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
751817
// Remove src_loc attributes
752818
FlatMapNodes::visit(krate, |mut item: P<Item>| {
753819
item.attrs.retain(|attr| !is_c2rust_attr(attr, "src_loc"));
820+
821+
if let ItemKind::Impl(impl_) = &mut item.kind {
822+
for item in &mut impl_.items {
823+
item.attrs.retain(|attr| !is_c2rust_attr(attr, "src_loc"));
824+
}
825+
}
826+
754827
smallvec![item]
755828
});
756829
FlatMapNodes::visit(krate, |mut item: P<ForeignItem>| {
@@ -1122,10 +1195,23 @@ struct MovedDecl {
11221195
namespace: Namespace,
11231196
loc: Option<SrcLoc>,
11241197
parent_header: HeaderInfo,
1198+
impl_: Option<MovedDeclImpl>,
1199+
}
1200+
1201+
#[derive(Debug, Clone)]
1202+
struct MovedDeclImpl {
1203+
item: P<Item>,
1204+
parent_header: HeaderInfo,
11251205
}
11261206

11271207
impl MovedDecl {
1128-
fn new<T>(decl: T, def_id: DefId, namespace: Namespace, parent_header: HeaderInfo) -> Self
1208+
fn new<T>(
1209+
decl: T,
1210+
def_id: DefId,
1211+
namespace: Namespace,
1212+
parent_header: HeaderInfo,
1213+
impl_: Option<MovedDeclImpl>,
1214+
) -> Self
11291215
where
11301216
T: Into<DeclKind>,
11311217
{
@@ -1142,6 +1228,7 @@ impl MovedDecl {
11421228
namespace,
11431229
loc,
11441230
parent_header,
1231+
impl_,
11451232
}
11461233
}
11471234

@@ -1328,14 +1415,12 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
13281415

13291416
/// Add an item into the module. If it has a name conflict with an existing
13301417
/// item, choose the definition item over any declarations.
1331-
pub fn insert_item(&mut self, mut item: P<Item>, parent_header: HeaderInfo) -> bool {
1332-
let namespace = self.cx.item_namespace(&item);
1333-
let new_def_id = self.cx.node_def_id(item.id);
1334-
let ident = if let ItemKind::Use(tree) = &item.kind {
1335-
tree.ident()
1336-
} else {
1337-
item.ident
1338-
};
1418+
pub fn insert_item(
1419+
&mut self,
1420+
mut item: P<Item>,
1421+
parent_header: HeaderInfo,
1422+
impl_: Option<MovedDeclImpl>,
1423+
) -> bool {
13391424
match &item.kind {
13401425
// We have to disambiguate anonymous items by contents,
13411426
// since we don't have a proper Ident.
@@ -1344,15 +1429,15 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
13441429
// ident_map.
13451430
ItemKind::Use(tree) if is_nested(tree) => {
13461431
for u in split_uses(item).into_iter() {
1347-
self.insert_item(u, parent_header.clone());
1432+
self.insert_item(u, parent_header.clone(), impl_.clone());
13481433
}
13491434
true
13501435
}
13511436

13521437
// Keep function definitions, if any
13531438
ItemKind::Fn(..) => false,
13541439

1355-
// Don't keep impl blocks, these are expanded from macros anyway
1440+
// These should have already been removed before.
13561441
ItemKind::Impl(..) => true,
13571442

13581443
// We collect all ForeignItems and later filter out any idents
@@ -1372,11 +1457,24 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
13721457
// we don't have any items with the same name but different
13731458
// contents.
13741459
_ => {
1460+
let namespace = self.cx.item_namespace(&item);
1461+
let new_def_id = self.cx.node_def_id(item.id);
1462+
let ident = if let ItemKind::Use(tree) = &item.kind {
1463+
tree.ident()
1464+
} else {
1465+
item.ident
1466+
};
13751467
let unnamed = ident.as_str().contains("C2Rust_Unnamed");
1376-
let def_id_mapping = match self.find_item(&item, namespace.unwrap()) {
1468+
let impl_item = impl_.as_ref().map(|impl_| &*impl_.item);
1469+
let def_id_mapping = match self.find_item(&item, namespace.unwrap(), impl_item) {
13771470
ContainsDecl::NotContained => {
1378-
let new_item =
1379-
MovedDecl::new(item, new_def_id, namespace.unwrap(), parent_header);
1471+
let new_item = MovedDecl::new(
1472+
item,
1473+
new_def_id,
1474+
namespace.unwrap(),
1475+
parent_header,
1476+
impl_,
1477+
);
13801478
if unnamed {
13811479
self.unnamed_items[namespace.unwrap()].push(new_item);
13821480
} else {
@@ -1396,17 +1494,27 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
13961494
ContainsDecl::Use(existing) => {
13971495
let existing_def_id = existing.def_id;
13981496
existing.join_visibility(&item.vis.kind);
1399-
*existing =
1400-
MovedDecl::new(item, new_def_id, namespace.unwrap(), parent_header);
1497+
*existing = MovedDecl::new(
1498+
item,
1499+
new_def_id,
1500+
namespace.unwrap(),
1501+
parent_header,
1502+
impl_,
1503+
);
14011504
Some((existing_def_id, new_def_id))
14021505
}
14031506

14041507
ContainsDecl::Equivalent(existing) if existing.is_foreign() => {
14051508
let existing_def_id = existing.def_id;
14061509
item.vis.kind =
14071510
join_visibility(&existing.visibility().kind, &item.vis.kind);
1408-
*existing =
1409-
MovedDecl::new(item, new_def_id, namespace.unwrap(), parent_header);
1511+
*existing = MovedDecl::new(
1512+
item,
1513+
new_def_id,
1514+
namespace.unwrap(),
1515+
parent_header,
1516+
impl_,
1517+
);
14101518
Some((existing_def_id, new_def_id))
14111519
}
14121520

@@ -1432,6 +1540,7 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
14321540
new_def_id,
14331541
namespace,
14341542
parent_header.clone(),
1543+
None,
14351544
);
14361545
if unnamed {
14371546
self.unnamed_items[namespace].push(new_item);
@@ -1451,6 +1560,7 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
14511560
new_def_id,
14521561
namespace,
14531562
parent_header.clone(),
1563+
None,
14541564
);
14551565
Some((existing_def_id, new_def_id))
14561566
}
@@ -1544,6 +1654,17 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
15441654
foreign_items.entry(abi).or_default().push(fi);
15451655
}
15461656
}
1657+
1658+
// If there is an impl item, add it now.
1659+
if let Some(impl_) = item.impl_ {
1660+
let cur_mod_name = impl_.parent_header.ident;
1661+
let i = impl_.item;
1662+
if last_item_mod != Some(cur_mod_name) {
1663+
st.add_comment(i.id, make_header_comment(last_item_mod, cur_mod_name));
1664+
last_item_mod = Some(cur_mod_name);
1665+
}
1666+
items.push(i);
1667+
}
15471668
}
15481669

15491670
let foreign_mods = foreign_items
@@ -1553,14 +1674,30 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
15531674
foreign_mods.chain(items.into_iter()).collect()
15541675
}
15551676

1556-
fn find_item<'b>(&'b mut self, item: &Item, namespace: Namespace) -> ContainsDecl<'b> {
1677+
fn find_item<'b>(
1678+
&'b mut self,
1679+
item: &Item,
1680+
namespace: Namespace,
1681+
impl_item: Option<&Item>,
1682+
) -> ContainsDecl<'b> {
15571683
let ident = if let ItemKind::Use(tree) = &item.kind {
15581684
tree.ident()
15591685
} else {
15601686
item.ident
15611687
};
15621688
assert!(ident.name != kw::Empty);
15631689

1690+
let impl_is_compatible = |existing_decl: &MovedDecl| -> bool {
1691+
match (impl_item, &existing_decl.impl_) {
1692+
(None, None) => true,
1693+
(Some(impl_item), Some(existing_impl)) => {
1694+
self.cx
1695+
.compatible_types(impl_item, &existing_impl.item, false)
1696+
}
1697+
_ => false,
1698+
}
1699+
};
1700+
15641701
if ident.as_str().contains("C2Rust_Unnamed") {
15651702
for existing_decl in self.unnamed_items[namespace].iter_mut() {
15661703
match &existing_decl.kind {
@@ -1571,7 +1708,9 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
15711708
| ItemKind::Enum(..) => {
15721709
// Does the new item match the existing item, except
15731710
// for unnamed names?
1574-
if item.kind.unnamed_equiv(&existing_item.kind) {
1711+
if item.kind.unnamed_equiv(&existing_item.kind)
1712+
&& impl_is_compatible(existing_decl)
1713+
{
15751714
return ContainsDecl::Equivalent(existing_decl);
15761715
}
15771716
}
@@ -1616,7 +1755,9 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
16161755
// Otherwise make sure these items are structurally
16171756
// equivalent.
16181757
_ => {
1619-
if self.cx.compatible_types(&item, &existing_item, true) {
1758+
if self.cx.compatible_types(&item, &existing_item, true)
1759+
&& impl_is_compatible(existing_decl)
1760+
{
16201761
return ContainsDecl::Equivalent(existing_decl);
16211762
}
16221763
}

0 commit comments

Comments
 (0)