logicaffeine_compile/codegen/slice.rs
1//! Per-function codegen slicing (HOTSWAP Axis-3 / P14a).
2//!
3//! The AOT-native tier compiles ONE annotated function into a loadable artifact, so it
4//! needs that function plus everything it transitively calls — and nothing else.
5//! [`function_slice`] reduces a program's statements to exactly that closure: the
6//! target `FunctionDef` and every function reachable from it through the call graph,
7//! dropping `Main` and unrelated functions. Type definitions live in the
8//! `TypeRegistry` (threaded to codegen separately), so only `FunctionDef`s are
9//! filtered here. The reachable set comes from the shared [`CallGraph`].
10
11use logicaffeine_base::{Interner, Symbol};
12use logicaffeine_language::ast::Stmt;
13
14use crate::analysis::callgraph::CallGraph;
15
16/// The statements needed to compile `target` standalone: the `target` function plus
17/// every function reachable from it through the call graph (transitively). `Main` and
18/// top-level functions unreachable from `target` are dropped; definition order is
19/// preserved.
20pub fn function_slice<'a>(stmts: &[Stmt<'a>], target: Symbol, interner: &Interner) -> Vec<Stmt<'a>> {
21 let cg = CallGraph::build(stmts, interner);
22 let mut keep = cg.reachable_from(target);
23 keep.insert(target);
24 stmts
25 .iter()
26 .filter(|s| matches!(s, Stmt::FunctionDef { name, .. } if keep.contains(name)))
27 .cloned()
28 .collect()
29}