Files
RustAst/src/ast/compiler/optimizer/inliner.rs
T
Michael Schimmel bf86c76bb6 Refactor: Use root_purity instead of global_purity
This commit refactors the purity analysis from using a
`HashMap<GlobalIdx, Purity>` to a `Vec<Purity>` indexed by
`GlobalIdx.0`.

This change simplifies the data structure and makes purity lookups more
efficient. The `Binder`'s `globals` field has also been removed as it
was not being used.
2026-03-12 16:57:06 +01:00

179 lines
5.5 KiB
Rust

use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, LocalSlot};
use crate::ast::types::{Purity, Value};
use crate::ast::vm::Closure;
use std::cell::RefCell;
use std::collections::HashSet;
use std::rc::Rc;
use super::substitution_map::SubstitutionMap;
use super::utils::UsageInfo;
pub struct Inliner<'a> {
pub globals: &'a Option<Rc<RefCell<Vec<Value>>>>,
pub root_purity: &'a Option<Rc<RefCell<Vec<Purity>>>>,
}
impl<'a> Inliner<'a> {
pub fn new(
globals: &'a Option<Rc<RefCell<Vec<Value>>>>,
root_purity: &'a Option<Rc<RefCell<Vec<Purity>>>>,
) -> Self {
Self {
globals,
root_purity,
}
}
pub fn is_inlinable_value(&self, val: &Value, addr: Address) -> bool {
let type_ok = match val {
Value::Int(_)
| Value::Float(_)
| Value::Bool(_)
| Value::Text(_)
| Value::Keyword(_)
| Value::Record(_, _)
| Value::DateTime(_) => true,
Value::Object(obj) => {
if let Some(closure) = obj.as_any().downcast_ref::<Closure>() {
closure.upvalues.is_empty() && !closure.function_node.ty.is_recursive
} else {
false
}
}
_ => false,
};
if !type_ok {
return false;
}
if let Address::Global(idx) = addr {
if let Some(purity_rc) = &self.root_purity {
let purity = purity_rc
.borrow()
.get(idx.0 as usize)
.cloned()
.unwrap_or(Purity::Impure);
return purity >= Purity::Pure;
}
return false;
}
true
}
pub fn prepare_beta_reduction(
&self,
params: &AnalyzedNode,
arg_vals: &[Rc<AnalyzedNode>],
body: &AnalyzedNode,
sub: &mut SubstitutionMap,
) -> Option<()> {
let mut body_usage = UsageInfo::default();
body_usage.collect(body);
let mut slot_index = 0;
self.map_params_to_args(params, arg_vals, &mut slot_index, sub, &body_usage);
if slot_index != arg_vals.len() {
return None;
}
let mut param_slots = HashSet::new();
self.collect_parameter_slots_set(params, &mut param_slots);
for slot in param_slots {
let addr = Address::Local(slot);
if (body_usage.is_used(&addr) || body_usage.is_assigned(&addr))
&& sub.get_value(&addr).is_none()
&& !sub.ast_substitutions.contains_key(&addr)
{
return None;
}
}
if sub.values.is_empty() && sub.ast_substitutions.is_empty() && !arg_vals.is_empty() {
return None;
}
Some(())
}
pub fn map_params_to_args(
&self,
pattern: &AnalyzedNode,
args: &[Rc<AnalyzedNode>],
offset: &mut usize,
sub: &mut SubstitutionMap,
body_usage: &UsageInfo,
) {
match &pattern.kind {
BoundKind::Define { addr, .. } => {
if let Some(arg) = args.get(*offset)
&& !body_usage.is_assigned(addr)
{
if let BoundKind::Constant(val) = &arg.kind {
sub.add_value(*addr, val.clone());
} else if let BoundKind::Lambda { upvalues, .. } = &arg.kind
&& upvalues.is_empty()
{
sub.add_ast_substitution(*addr, (**arg).clone());
} else if let BoundKind::Get {
addr: Address::Global(_),
..
} = &arg.kind
{
sub.add_ast_substitution(*addr, (**arg).clone());
}
}
if let Address::Local(slot) = addr {
sub.map_slot(*slot);
}
*offset += 1;
}
BoundKind::Tuple { elements } => {
for el in elements {
self.map_params_to_args(el, args, offset, sub, body_usage);
}
}
_ => {}
}
}
pub fn collect_parameter_slots_set(&self, node: &AnalyzedNode, slots: &mut HashSet<LocalSlot>) {
match &node.kind {
BoundKind::Define {
addr: Address::Local(slot),
..
} => {
slots.insert(*slot);
}
BoundKind::Tuple { elements } => {
for el in elements {
self.collect_parameter_slots_set(el, slots);
}
}
_ => {}
}
}
pub fn collect_parameter_slots(&self, node: &AnalyzedNode, sub: &mut SubstitutionMap) {
match &node.kind {
BoundKind::Define {
addr: Address::Local(slot),
..
} => {
sub.slot_mapping.insert(*slot, *slot);
sub.next_slot = sub.next_slot.max(slot.0 + 1);
}
BoundKind::Tuple { elements } => {
for el in elements {
self.collect_parameter_slots(el, sub);
}
}
_ => {}
}
}
}