diff --git a/src/ast/compiler/optimizer.rs b/src/ast/compiler/optimizer.rs index e13ae2c..79d7805 100644 --- a/src/ast/compiler/optimizer.rs +++ b/src/ast/compiler/optimizer.rs @@ -129,22 +129,15 @@ impl Optimizer { let (new_kind, metrics) = match node.kind { BoundKind::Get { addr, ref name } => { if !sub.assigned.contains(&addr) { - // 1. Try inlining from current substitution map (locals/globals/upvalues) - if let Some(val) = sub.get_value(&addr) { - // For globals, only inline if it's a known "safe" value - let can_inline = match addr { - Address::Global(idx) => self.is_inlinable_value(val, Some(idx)), - _ => true, - }; - if can_inline { - return self.make_constant_node(val.clone(), &node); - } + // 1. Try inlining from current value substitution map (locals/globals/upvalues) + if let Some(val) = sub.get_value(&addr) + && self.is_inlinable_value(val, addr) + { + return self.make_constant_node(val.clone(), &node); } - // 2. Special case: Local-only AST inlining (for non-constant but pure expressions) - if let Address::Local(slot) = addr - && let Some(inlined_node) = sub.ast_locals.get(&slot) - { + // 2. Try inlining from AST substitution map (pure expressions) + if let Some(inlined_node) = sub.ast_substitutions.get(&addr) { return inlined_node.clone(); } @@ -154,7 +147,7 @@ impl Optimizer { { let globals = globals_rc.borrow(); if let Some(val) = globals.get(idx as usize) - && self.is_inlinable_value(val, Some(idx)) + && self.is_inlinable_value(val, addr) { return self.make_constant_node(val.clone(), &node); } @@ -597,8 +590,9 @@ impl Optimizer { } } - fn is_inlinable_value(&self, val: &Value, _global_idx: Option) -> bool { - match val { + fn is_inlinable_value(&self, val: &Value, addr: Address) -> bool { + // 1. Basic check: is the type itself inlinable (Constants, pure Closures)? + let type_ok = match val { Value::Int(_) | Value::Float(_) | Value::Bool(_) @@ -613,7 +607,27 @@ impl Optimizer { } } _ => false, + }; + + if !type_ok { + return false; } + + // 2. For Globals: check if they are actually pure/stable + if let Address::Global(idx) = addr { + if let Some(purity_rc) = &self.global_purity { + let purity = purity_rc + .borrow() + .get(&idx) + .cloned() + .unwrap_or(Purity::Impure); + return purity >= Purity::Pure; + } + // If no purity info is available, we assume the global is unstable (safer) + return false; + } + + true // Locals/Upvalues that reach here and passed the type check are inlinable } fn make_constant_node(&self, val: Value, template: &AnalyzedNode) -> AnalyzedNode { @@ -710,13 +724,13 @@ impl Optimizer { let addr = Address::Local(slot); if (body_usage.is_used(&addr) || body_usage.is_assigned(&addr)) && sub.get_value(&addr).is_none() - && !sub.ast_locals.contains_key(&slot) + && !sub.ast_substitutions.contains_key(&addr) { return None; } } - if sub.values.is_empty() && sub.ast_locals.is_empty() && !arg_vals.is_empty() { + if sub.values.is_empty() && sub.ast_substitutions.is_empty() && !arg_vals.is_empty() { return None; } @@ -774,16 +788,14 @@ impl Optimizer { sub.add_value(*addr, val.clone()); } else if let BoundKind::Lambda { upvalues, .. } = &arg.kind && upvalues.is_empty() - && let Address::Local(slot) = addr { - sub.add_ast_local(*slot, arg.clone()); + sub.add_ast_substitution(*addr, arg.clone()); } else if let BoundKind::Get { addr: Address::Global(_), .. } = &arg.kind - && let Address::Local(slot) = addr { - sub.add_ast_local(*slot, arg.clone()); + sub.add_ast_substitution(*addr, arg.clone()); } } @@ -941,7 +953,7 @@ impl Optimizer { struct SubstitutionMap { values: HashMap, - ast_locals: HashMap, + ast_substitutions: HashMap, slot_mapping: HashMap, assigned: HashSet
, next_slot: u32, @@ -953,7 +965,7 @@ impl SubstitutionMap { fn new() -> Self { Self { values: HashMap::new(), - ast_locals: HashMap::new(), + ast_substitutions: HashMap::new(), slot_mapping: HashMap::new(), assigned: HashSet::new(), next_slot: 0, @@ -962,8 +974,8 @@ impl SubstitutionMap { } } - fn add_ast_local(&mut self, slot: u32, node: AnalyzedNode) { - self.ast_locals.insert(slot, node); + fn add_ast_substitution(&mut self, addr: Address, node: AnalyzedNode) { + self.ast_substitutions.insert(addr, node); } fn map_slot(&mut self, old_slot: u32) -> u32 {