Skip to content

Commit e7a282b

Browse files
junxzm1990claude
andcommitted
[move-model] Track struct usage during build instead of lazy computation
Replace the expensive lazy computation in StructEnv::get_using_functions() which iterates over all modules and all functions with eager tracking during function body translation. - Add using_functions field to StructEntry to accumulate usage during build - In def_ana_fun, after translating function body, collect used structs via struct_usage() and update corresponding StructEntry - Pass the collected using_functions from StructEntry to StructData during finalization This eliminates the O(modules * functions) scan on every get_using_functions() call, making unused struct detection much more efficient. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent f6b3e09 commit e7a282b

File tree

2 files changed

+25
-3
lines changed

2 files changed

+25
-3
lines changed

third_party/move/move-model/src/builder/model_builder.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ pub(crate) struct StructEntry {
130130
pub is_empty_struct: bool,
131131
pub is_native: bool,
132132
pub visibility: Visibility,
133+
/// Functions that use this struct
134+
pub using_functions: BTreeSet<QualifiedId<FunId>>,
133135
}
134136

135137
#[derive(Debug, Clone)]
@@ -392,6 +394,7 @@ impl<'env> ModelBuilder<'env> {
392394
is_empty_struct: false,
393395
is_native,
394396
visibility,
397+
using_functions: BTreeSet::new(),
395398
};
396399
self.struct_table.insert(name.clone(), entry);
397400
self.reverse_struct_table

third_party/move/move-model/src/builder/module_builder.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ use crate::{
2222
metadata::lang_feature_versions::LANGUAGE_VERSION_FOR_PUBLIC_STRUCT,
2323
model::{
2424
self, EqIgnoringLoc, FieldData, FieldId, FunId, FunctionData, FunctionKind, FunctionLoc,
25-
Loc, ModuleId, MoveIrLoc, NamedConstantData, NamedConstantId, NodeId, Parameter, SchemaId,
26-
SpecFunId, SpecVarId, StructData, StructId, TypeParameter, TypeParameterKind,
25+
Loc, ModuleId, MoveIrLoc, NamedConstantData, NamedConstantId, NodeId, Parameter,
26+
QualifiedId, SchemaId, SpecFunId, SpecVarId, StructData, StructId, TypeParameter,
27+
TypeParameterKind,
2728
},
2829
options::ModelBuilderOptions,
2930
pragmas::{
@@ -1490,6 +1491,24 @@ impl ModuleBuilder<'_, '_> {
14901491
et.finalize_types(true);
14911492
et.check_mutable_borrow_field(&translated);
14921493
et.check_lambda_types(&translated);
1494+
1495+
// Track struct usage for unused struct detection
1496+
let mut used_structs = BTreeSet::new();
1497+
translated.struct_usage(self.parent.env, &mut used_structs);
1498+
let fun_qid = QualifiedId {
1499+
module_id: self.module_id,
1500+
id: FunId::new(full_name.symbol),
1501+
};
1502+
for struct_id in used_structs {
1503+
if let Some(struct_entry) = self
1504+
.parent
1505+
.struct_table
1506+
.get_mut(&self.parent.reverse_struct_table.get(&(struct_id.module_id, struct_id.id)).expect("struct exists"))
1507+
{
1508+
struct_entry.using_functions.insert(fun_qid);
1509+
}
1510+
}
1511+
14931512
assert!(self.fun_defs.insert(full_name.symbol, translated).is_none());
14941513
if let Some(specifiers) = access_specifiers {
14951514
assert!(self
@@ -3624,7 +3643,7 @@ impl ModuleBuilder<'_, '_> {
36243643
visibility: entry.visibility,
36253644
has_package_visibility: self.package_structs.contains(&entry.struct_id),
36263645
is_empty_struct: entry.is_empty_struct,
3627-
using_funs: RefCell::new(None),
3646+
using_funs: RefCell::new(Some(entry.using_functions.clone())),
36283647
};
36293648
struct_data.insert(StructId::new(name.symbol), data);
36303649
if entry.visibility != Visibility::Private

0 commit comments

Comments
 (0)