Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions third_party/move/move-model/src/builder/module_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4844,6 +4844,7 @@ impl ModuleBuilder<'_, '_> {
using_funs: RefCell::default(),
transitive_closure_of_used_funs: RefCell::default(),
used_functions_with_transitive_inline: RefCell::default(),
using_functions_with_transitive_inline: RefCell::default(),
used_structs: RefCell::default(),
};
function_data.insert(fun_id, data);
Expand Down Expand Up @@ -4890,6 +4891,7 @@ impl ModuleBuilder<'_, '_> {
using_funs: RefCell::default(),
transitive_closure_of_used_funs: RefCell::default(),
used_functions_with_transitive_inline: RefCell::default(),
using_functions_with_transitive_inline: RefCell::default(),
used_structs: RefCell::default(),
};
function_data.insert(fun_id, data);
Expand Down
42 changes: 42 additions & 0 deletions third_party/move/move-model/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2229,6 +2229,7 @@ impl GlobalEnv {
*data.using_funs.borrow_mut() = None;
*data.transitive_closure_of_used_funs.borrow_mut() = None;
*data.used_functions_with_transitive_inline.borrow_mut() = None;
*data.using_functions_with_transitive_inline.borrow_mut() = None;
// Set the new function definition.
data.def = Some(def);
}
Expand Down Expand Up @@ -2303,6 +2304,7 @@ impl GlobalEnv {
using_funs: RefCell::new(None),
transitive_closure_of_used_funs: RefCell::new(None),
used_functions_with_transitive_inline: RefCell::new(None),
using_functions_with_transitive_inline: RefCell::new(None),
used_structs: RefCell::new(None),
};
assert!(self
Expand Down Expand Up @@ -2375,6 +2377,7 @@ impl GlobalEnv {
using_funs: RefCell::new(None),
transitive_closure_of_used_funs: RefCell::new(None),
used_functions_with_transitive_inline: RefCell::new(None),
using_functions_with_transitive_inline: RefCell::new(None),
used_structs: RefCell::new(None),
}
}
Expand Down Expand Up @@ -4923,6 +4926,11 @@ pub struct FunctionData {
/// A cache for used functions including ones obtained by transitively traversing used inline functions.
pub(crate) used_functions_with_transitive_inline: RefCell<Option<BTreeSet<QualifiedId<FunId>>>>,

/// A cache for using functions with direct inline callers replaced by their (transitive) callers,
/// reflecting the post-inlining call graph.
pub(crate) using_functions_with_transitive_inline:
RefCell<Option<BTreeSet<QualifiedId<FunId>>>>,

/// A cache for used structs.
pub(crate) used_structs: RefCell<Option<BTreeSet<QualifiedId<StructId>>>>,
}
Expand Down Expand Up @@ -4958,6 +4966,7 @@ impl FunctionData {
using_funs: RefCell::new(None),
transitive_closure_of_used_funs: RefCell::new(None),
used_functions_with_transitive_inline: RefCell::new(None),
using_functions_with_transitive_inline: RefCell::new(None),
used_structs: RefCell::new(None),
}
}
Expand Down Expand Up @@ -5813,6 +5822,39 @@ impl<'env> FunctionEnv<'env> {
set
}

/// Get the functions that effectively use (call) this one after inline expansion.
/// Direct callers that are themselves inline functions are replaced by their
/// (transitive) callers, because after inlining those inline callers no longer
/// contain a call site — their callers do.
pub fn get_using_functions_with_transitive_inline(&self) -> BTreeSet<QualifiedId<FunId>> {
if let Some(using) = &*self.data.using_functions_with_transitive_inline.borrow() {
return using.clone();
}
let mut result = BTreeSet::new();
let mut visited = BTreeSet::new();
Comment thread
vineethk marked this conversation as resolved.
visited.insert(self.get_qualified_id());
let mut reachable_funcs = VecDeque::new();
reachable_funcs.push_back(self.clone());
while let Some(fnc) = reachable_funcs.pop_front() {
for user in fnc.get_using_functions().expect("call info available") {
Comment thread
vineethk marked this conversation as resolved.
if !visited.insert(user) {
continue;
}
let user_fun = self.module_env.env.get_function(user);
if user_fun.is_inline() {
reachable_funcs.push_back(user_fun);
} else {
result.insert(user);
}
Comment thread
vineethk marked this conversation as resolved.
}
}
*self
.data
.using_functions_with_transitive_inline
.borrow_mut() = Some(result.clone());
result
}

/// Get used structs/enums including ones obtained by transitively traversing used inline functions
pub fn get_used_structs_with_transitive_inline(&self) -> BTreeSet<QualifiedId<StructId>> {
if let Some(used_structs) = &*self.data.used_structs.borrow() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,13 @@ pub fn has_users(func: &FunctionEnv) -> bool {

/// Returns true if the function has at least one non-self caller, and all
/// callers are within the same module.
///
/// Direct callers that are inline functions are replaced by their (transitive)
/// callers, because inline bodies are expanded at call sites during compilation:
/// after inlining, this function is effectively called from wherever the inline
/// caller is called.
pub fn has_same_module_users_only(func: &FunctionEnv) -> bool {
let Some(using_funs) = func.get_using_functions() else {
return false;
};
let using_funs = func.get_using_functions_with_transitive_inline();
let func_qfid = func.get_qualified_id();
let func_module_id = func.module_env.get_id();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

No errors or warnings!
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module 0xc0ffee::m {
package fun package_inner(): u64 {
42
}

package inline fun outer(): u64 {
Comment thread
vineethk marked this conversation as resolved.
package_inner()
}
}

module 0xc0ffee::n {
use 0xc0ffee::m;

public fun call_outer(): u64 {
m::outer()
}
}
Loading