diff --git a/src/ast/compiler/analyzer.rs b/src/ast/compiler/analyzer.rs index 2903209..a95c710 100644 --- a/src/ast/compiler/analyzer.rs +++ b/src/ast/compiler/analyzer.rs @@ -86,11 +86,11 @@ impl<'a> Analyzer<'a> { BoundKind::FieldAccessor(k) => (BoundKind::FieldAccessor(*k), Purity::Pure), BoundKind::GetField { rec, field } => { - let rec_m = self.visit(Rc::new((**rec).clone())); + let rec_m = self.visit(rec.clone()); let p = rec_m.ty.purity; ( BoundKind::GetField { - rec: Box::new(rec_m), + rec: Rc::new(rec_m), field: *field, }, p, @@ -98,11 +98,11 @@ impl<'a> Analyzer<'a> { } BoundKind::Set { addr, value } => { - let val_m = self.visit(Rc::new((**value).clone())); + let val_m = self.visit(value.clone()); ( BoundKind::Set { addr: *addr, - value: Box::new(val_m), + value: Rc::new(val_m), }, Purity::Impure, ) @@ -115,14 +115,14 @@ impl<'a> Analyzer<'a> { value, captured_by, } => { - let val_m = self.visit(Rc::new((**value).clone())); + let val_m = self.visit(value.clone()); let p = val_m.ty.purity; ( BoundKind::Define { name: name.clone(), addr: *addr, kind: *kind, - value: Box::new(val_m), + value: Rc::new(val_m), captured_by: captured_by.clone(), }, p, @@ -134,9 +134,9 @@ impl<'a> Analyzer<'a> { then_br, else_br, } => { - let cond_m = self.visit(Rc::new((**cond).clone())); - let then_m = self.visit(Rc::new((**then_br).clone())); - let else_m = else_br.as_ref().map(|e| self.visit(Rc::new((**e).clone()))); + let cond_m = self.visit(cond.clone()); + let then_m = self.visit(then_br.clone()); + let else_m = else_br.as_ref().map(|e| self.visit(e.clone())); let mut p = cond_m.ty.purity.min(then_m.ty.purity); if let Some(ref em) = else_m { @@ -144,9 +144,9 @@ impl<'a> Analyzer<'a> { } ( BoundKind::If { - cond: Box::new(cond_m), - then_br: Box::new(then_m), - else_br: else_m.map(Box::new), + cond: Rc::new(cond_m), + then_br: Rc::new(then_m), + else_br: else_m.map(Rc::new), }, p, ) @@ -176,20 +176,20 @@ impl<'a> Analyzer<'a> { } BoundKind::Destructure { pattern, value } => { - let pat_m = self.visit(Rc::new((**pattern).clone())); - let val_m = self.visit(Rc::new((**value).clone())); + let pat_m = self.visit(pattern.clone()); + let val_m = self.visit(value.clone()); ( BoundKind::Destructure { - pattern: Box::new(pat_m), - value: Box::new(val_m), + pattern: Rc::new(pat_m), + value: Rc::new(val_m), }, Purity::Impure, ) } BoundKind::Call { callee, args } => { - let callee_m = self.visit(Rc::new((**callee).clone())); - let args_m = self.visit(Rc::new((**args).clone())); + let callee_m = self.visit(callee.clone()); + let args_m = self.visit(args.clone()); if let BoundKind::Get { addr: Address::Global(idx), @@ -217,22 +217,22 @@ impl<'a> Analyzer<'a> { let p = callee_m.ty.purity.min(args_m.ty.purity).min(p_func); ( BoundKind::Call { - callee: Box::new(callee_m), - args: Box::new(args_m), + callee: Rc::new(callee_m), + args: Rc::new(args_m), }, p, ) } BoundKind::Again { args } => { - let args_m = self.visit(Rc::new((**args).clone())); + let args_m = self.visit(args.clone()); if let Some(lambda_id) = self.lambda_stack.last() { self.recursive_identities.insert(lambda_id.clone()); is_recursive = true; } ( BoundKind::Again { - args: Box::new(args_m), + args: Rc::new(args_m), }, Purity::Impure, ) @@ -244,9 +244,9 @@ impl<'a> Analyzer<'a> { } => { let mut analyzed_inputs = Vec::with_capacity(inputs.len()); for input in inputs { - analyzed_inputs.push(self.visit(Rc::new(input.clone()))); + analyzed_inputs.push(Rc::new(self.visit(input.clone()))); } - let a_lambda = Box::new(self.visit(Rc::new((**lambda).clone()))); + let a_lambda = Rc::new(self.visit(lambda.clone())); ( BoundKind::Pipe { inputs: analyzed_inputs, @@ -261,9 +261,9 @@ impl<'a> Analyzer<'a> { let mut new_exprs = Vec::with_capacity(exprs.len()); let mut p = Purity::Pure; for e in exprs { - let em = self.visit(Rc::new(e.clone())); + let em = self.visit(e.clone()); p = p.min(em.ty.purity); - new_exprs.push(em); + new_exprs.push(Rc::new(em)); } (BoundKind::Block { exprs: new_exprs }, p) } @@ -272,9 +272,9 @@ impl<'a> Analyzer<'a> { let mut new_elements = Vec::with_capacity(elements.len()); let mut p = Purity::Pure; for e in elements { - let em = self.visit(Rc::new(e.clone())); + let em = self.visit(e.clone()); p = p.min(em.ty.purity); - new_elements.push(em); + new_elements.push(Rc::new(em)); } ( BoundKind::Tuple { @@ -288,9 +288,9 @@ impl<'a> Analyzer<'a> { let mut new_values = Vec::with_capacity(values.len()); let mut p = Purity::Pure; for v in values { - let vm = self.visit(Rc::new(v.clone())); + let vm = self.visit(v.clone()); p = p.min(vm.ty.purity); - new_values.push(vm); + new_values.push(Rc::new(vm)); } ( BoundKind::Record { @@ -305,11 +305,11 @@ impl<'a> Analyzer<'a> { original_call, bound_expanded, } => { - let expanded_m = self.visit(Rc::new((**bound_expanded).clone())); + let expanded_m = self.visit(bound_expanded.clone()); ( BoundKind::Expansion { original_call: original_call.clone(), - bound_expanded: Box::new(expanded_m.clone()), + bound_expanded: Rc::new(expanded_m.clone()), }, expanded_m.ty.purity, ) diff --git a/src/ast/compiler/binder.rs b/src/ast/compiler/binder.rs index 857aa9f..66a968e 100644 --- a/src/ast/compiler/binder.rs +++ b/src/ast/compiler/binder.rs @@ -215,14 +215,14 @@ impl Binder { let then_br = self.bind(then_br, diag); let mut else_br_bound = None; if let Some(e) = else_br { - else_br_bound = Some(Box::new(self.bind(e, diag))); + else_br_bound = Some(Rc::new(self.bind(e, diag))); } self.make_node( node.identity.clone(), BoundKind::If { - cond: Box::new(cond), - then_br: Box::new(then_br), + cond: Rc::new(cond), + then_br: Rc::new(then_br), else_br: else_br_bound, }, ) @@ -246,7 +246,7 @@ impl Binder { name: name.clone(), addr, kind: crate::ast::compiler::bound_nodes::DeclarationKind::Variable, - value: Box::new(val_node), + value: Rc::new(val_node), captured_by: Vec::new(), // Will be filled by post-pass }, ) @@ -263,8 +263,8 @@ impl Binder { self.make_node( node.identity.clone(), BoundKind::Destructure { - pattern: Box::new(target_node), - value: Box::new(val_node), + pattern: Rc::new(target_node), + value: Rc::new(val_node), }, ) } @@ -279,7 +279,7 @@ impl Binder { node.identity.clone(), BoundKind::Set { addr, - value: Box::new(val_node), + value: Rc::new(val_node), }, ) } else { @@ -290,8 +290,8 @@ impl Binder { self.make_node( node.identity.clone(), BoundKind::Destructure { - pattern: Box::new(target_node), - value: Box::new(val_node), + pattern: Rc::new(target_node), + value: Rc::new(val_node), }, ) } @@ -300,9 +300,9 @@ impl Binder { UntypedKind::Pipe { inputs, lambda } => { let mut bound_inputs = Vec::with_capacity(inputs.len()); for input in inputs { - bound_inputs.push(self.bind(input, diag)); + bound_inputs.push(Rc::new(self.bind(input, diag))); } - let bound_lambda = Box::new(self.bind(lambda.as_ref(), diag)); + let bound_lambda = Rc::new(self.bind(lambda.as_ref(), diag)); self.make_node( node.identity.clone(), BoundKind::Pipe { @@ -365,8 +365,8 @@ impl Binder { self.make_node( node.identity.clone(), BoundKind::Call { - callee: Box::new(callee), - args: Box::new(args), + callee: Rc::new(callee), + args: Rc::new(args), }, ) } @@ -383,7 +383,7 @@ impl Binder { self.make_node( node.identity.clone(), BoundKind::Again { - args: Box::new(args), + args: Rc::new(args), }, ) } @@ -391,7 +391,7 @@ impl Binder { UntypedKind::Block { exprs } => { let mut bound_exprs = Vec::new(); for expr in exprs { - bound_exprs.push(self.bind(expr, diag)); + bound_exprs.push(Rc::new(self.bind(expr, diag))); } self.make_node( node.identity.clone(), @@ -402,7 +402,7 @@ impl Binder { UntypedKind::Tuple { elements } => { let mut bound_elems = Vec::new(); for e in elements { - bound_elems.push(self.bind(e, diag)); + bound_elems.push(Rc::new(self.bind(e, diag))); } self.make_node( node.identity.clone(), @@ -433,7 +433,7 @@ impl Binder { Some(key_node.identity.clone()), ); } - bound_values.push(val_node); + bound_values.push(Rc::new(val_node)); } let layout = crate::ast::types::RecordLayout::get_or_create(layout_fields); @@ -453,7 +453,7 @@ impl Binder { node.identity.clone(), BoundKind::Expansion { original_call: Rc::from(call.as_ref().clone()), - bound_expanded: Box::new(bound_expanded), + bound_expanded: Rc::new(bound_expanded), }, ) } @@ -551,7 +551,7 @@ impl Binder { name: sym.clone(), addr, kind, - value: Box::new(self.make_node(node.identity.clone(), BoundKind::Nop)), + value: Rc::new(self.make_node(node.identity.clone(), BoundKind::Nop)), captured_by: Vec::new(), // Filled by post-pass }, ) @@ -562,7 +562,7 @@ impl Binder { UntypedKind::Tuple { elements } => { let mut bound_elems = Vec::new(); for e in elements { - bound_elems.push(self.bind_pattern(e, kind, diag)); + bound_elems.push(Rc::new(self.bind_pattern(e, kind, diag))); } self.make_node( node.identity.clone(), @@ -593,7 +593,7 @@ impl Binder { node.identity.clone(), BoundKind::Set { addr, - value: Box::new(self.make_node(node.identity.clone(), BoundKind::Nop)), + value: Rc::new(self.make_node(node.identity.clone(), BoundKind::Nop)), }, ) } else { @@ -603,7 +603,7 @@ impl Binder { UntypedKind::Tuple { elements } => { let mut bound_elems = Vec::new(); for e in elements { - bound_elems.push(self.bind_assign_pattern(e, diag)); + bound_elems.push(Rc::new(self.bind_assign_pattern(e, diag))); } self.make_node( node.identity.clone(), diff --git a/src/ast/compiler/bound_nodes.rs b/src/ast/compiler/bound_nodes.rs index e6e96a1..fe650f6 100644 --- a/src/ast/compiler/bound_nodes.rs +++ b/src/ast/compiler/bound_nodes.rs @@ -54,7 +54,7 @@ impl Clone for Box> { } } -/// Type alias for a node that has been bound. Defaults to untyped (T = ()). +/// A bound AST node, decorated with type or metric information T. pub type BoundNode = Node, T>; /// Type alias for a node that has been fully type-checked. @@ -91,7 +91,7 @@ pub enum BoundKind { // Variable Update (Assignment) Set { addr: Address, - value: Box>, + value: Rc>, }, // Variable Declaration (Unified for Local/Global/Parameter) @@ -99,7 +99,7 @@ pub enum BoundKind { name: Symbol, addr: Address, kind: DeclarationKind, - value: Box>, + value: Rc>, captured_by: Vec, }, @@ -108,20 +108,20 @@ pub enum BoundKind { /// Specialized field access (O(1) via RecordLayout) GetField { - rec: Box>, + rec: Rc>, field: crate::ast::types::Keyword, }, If { - cond: Box>, - then_br: Box>, - else_br: Option>>, + cond: Rc>, + then_br: Rc>, + else_br: Option>>, }, /// A destructuring operation (can be a definition or an assignment depending on the pattern) Destructure { - pattern: Box>, - value: Box>, + pattern: Rc>, + value: Rc>, }, Lambda { @@ -134,29 +134,29 @@ pub enum BoundKind { }, Call { - callee: Box>, - args: Box>, + callee: Rc>, + args: Rc>, }, Again { - args: Box>, + args: Rc>, }, Pipe { - inputs: Vec>, - lambda: Box>, + inputs: Vec>>, + lambda: Rc>, out_type: crate::ast::types::StaticType, }, Block { - exprs: Vec>, + exprs: Vec>>, }, Tuple { - elements: Vec>, + elements: Vec>>, }, Record { layout: std::sync::Arc, - values: Vec>, + values: Vec>>, }, /// An expanded macro call, preserving the original call for debugging and UI. @@ -164,7 +164,7 @@ pub enum BoundKind { /// The original call from the untyped AST. original_call: Rc>, /// The result of binding the expanded AST. - bound_expanded: Box>, + bound_expanded: Rc>, }, /// A diagnostic poison node, allowing compilation to continue after an error. @@ -194,7 +194,7 @@ where addr: ab, value: vb, }, - ) => aa == ab && va == vb, + ) => aa == ab && Rc::ptr_eq(va, vb), ( BoundKind::Define { name: na, @@ -210,12 +210,12 @@ where value: vb, captured_by: cb, }, - ) => na == nb && aa == ab && ka == kb && va == vb && ca == cb, + ) => na == nb && aa == ab && ka == kb && Rc::ptr_eq(va, vb) && ca == cb, (BoundKind::FieldAccessor(a), BoundKind::FieldAccessor(b)) => a == b, ( BoundKind::GetField { rec: ra, field: fa }, BoundKind::GetField { rec: rb, field: fb }, - ) => ra == rb && fa == fb, + ) => Rc::ptr_eq(ra, rb) && fa == fb, ( BoundKind::If { cond: ca, @@ -227,7 +227,11 @@ where then_br: tb, else_br: eb, }, - ) => ca == cb && ta == tb && ea == eb, + ) => Rc::ptr_eq(ca, cb) && Rc::ptr_eq(ta, tb) && match (ea, eb) { + (Some(a), Some(b)) => Rc::ptr_eq(a, b), + (None, None) => true, + _ => false, + }, ( BoundKind::Destructure { pattern: pa, @@ -237,7 +241,7 @@ where pattern: pb, value: vb, }, - ) => pa == pb && va == vb, + ) => Rc::ptr_eq(pa, pb) && Rc::ptr_eq(va, vb), ( BoundKind::Lambda { params: pa, @@ -251,7 +255,7 @@ where body: bb, positional_count: pcb, }, - ) => pa == pb && ua == ub && ba == bb && pca == pcb, + ) => Rc::ptr_eq(pa, pb) && ua == ub && Rc::ptr_eq(ba, bb) && pca == pcb, ( BoundKind::Call { callee: ca, @@ -261,10 +265,14 @@ where callee: cb, args: ab, }, - ) => ca == cb && aa == ab, - (BoundKind::Again { args: aa }, BoundKind::Again { args: ab }) => aa == ab, - (BoundKind::Block { exprs: ea }, BoundKind::Block { exprs: eb }) => ea == eb, - (BoundKind::Tuple { elements: ea }, BoundKind::Tuple { elements: eb }) => ea == eb, + ) => Rc::ptr_eq(ca, cb) && Rc::ptr_eq(aa, ab), + (BoundKind::Again { args: aa }, BoundKind::Again { args: ab }) => Rc::ptr_eq(aa, ab), + (BoundKind::Block { exprs: ea }, BoundKind::Block { exprs: eb }) => { + ea.len() == eb.len() && ea.iter().zip(eb.iter()).all(|(a, b)| Rc::ptr_eq(a, b)) + } + (BoundKind::Tuple { elements: ea }, BoundKind::Tuple { elements: eb }) => { + ea.len() == eb.len() && ea.iter().zip(eb.iter()).all(|(a, b)| Rc::ptr_eq(a, b)) + } ( BoundKind::Record { layout: la, @@ -274,7 +282,7 @@ where layout: lb, values: vb, }, - ) => std::sync::Arc::ptr_eq(la, lb) && va == vb, + ) => std::sync::Arc::ptr_eq(la, lb) && va.len() == vb.len() && va.iter().zip(vb.iter()).all(|(a, b)| Rc::ptr_eq(a, b)), ( BoundKind::Expansion { original_call: ca, @@ -284,9 +292,9 @@ where original_call: cb, bound_expanded: eb, }, - ) => Rc::ptr_eq(ca, cb) && ea == eb, + ) => Rc::ptr_eq(ca, cb) && Rc::ptr_eq(ea, eb), (BoundKind::Error, BoundKind::Error) => true, - (BoundKind::Extension(_), BoundKind::Extension(_)) => false, // Currently no equality for extensions + (BoundKind::Extension(_), BoundKind::Extension(_)) => false, _ => false, } } diff --git a/src/ast/compiler/captures.rs b/src/ast/compiler/captures.rs index fc9aae2..58eaf83 100644 --- a/src/ast/compiler/captures.rs +++ b/src/ast/compiler/captures.rs @@ -10,6 +10,7 @@ impl CapturePass { } fn transform(mut node: BoundNode, capture_map: &HashMap>) -> BoundNode { + use std::rc::Rc; match node.kind { BoundKind::Define { name, @@ -23,7 +24,7 @@ impl CapturePass { name, addr, kind, - value: Box::new(Self::transform(*value, capture_map)), + value: Rc::new(Self::transform(value.as_ref().clone(), capture_map)), captured_by, }; } @@ -34,16 +35,16 @@ impl CapturePass { else_br, } => { node.kind = BoundKind::If { - cond: Box::new(Self::transform(*cond, capture_map)), - then_br: Box::new(Self::transform(*then_br, capture_map)), - else_br: else_br.map(|e| Box::new(Self::transform(*e, capture_map))), + cond: Rc::new(Self::transform(cond.as_ref().clone(), capture_map)), + then_br: Rc::new(Self::transform(then_br.as_ref().clone(), capture_map)), + else_br: else_br.map(|e| Rc::new(Self::transform(e.as_ref().clone(), capture_map))), }; } BoundKind::Set { addr, value } => { node.kind = BoundKind::Set { addr, - value: Box::new(Self::transform(*value, capture_map)), + value: Rc::new(Self::transform(value.as_ref().clone(), capture_map)), }; } @@ -51,15 +52,15 @@ impl CapturePass { BoundKind::GetField { rec, field } => { node.kind = BoundKind::GetField { - rec: Box::new(Self::transform(*rec, capture_map)), + rec: Rc::new(Self::transform(rec.as_ref().clone(), capture_map)), field, }; } BoundKind::Destructure { pattern, value } => { node.kind = BoundKind::Destructure { - pattern: Box::new(Self::transform(*pattern, capture_map)), - value: Box::new(Self::transform(*value, capture_map)), + pattern: Rc::new(Self::transform(pattern.as_ref().clone(), capture_map)), + value: Rc::new(Self::transform(value.as_ref().clone(), capture_map)), }; } @@ -70,23 +71,23 @@ impl CapturePass { positional_count, } => { node.kind = BoundKind::Lambda { - params: std::rc::Rc::new(Self::transform(params.as_ref().clone(), capture_map)), + params: Rc::new(Self::transform(params.as_ref().clone(), capture_map)), upvalues, - body: std::rc::Rc::new(Self::transform(body.as_ref().clone(), capture_map)), + body: Rc::new(Self::transform(body.as_ref().clone(), capture_map)), positional_count, }; } BoundKind::Call { callee, args } => { node.kind = BoundKind::Call { - callee: Box::new(Self::transform(*callee, capture_map)), - args: Box::new(Self::transform(*args, capture_map)), + callee: Rc::new(Self::transform(callee.as_ref().clone(), capture_map)), + args: Rc::new(Self::transform(args.as_ref().clone(), capture_map)), }; } BoundKind::Again { args } => { node.kind = BoundKind::Again { - args: Box::new(Self::transform(*args, capture_map)), + args: Rc::new(Self::transform(args.as_ref().clone(), capture_map)), }; } BoundKind::Pipe { @@ -96,11 +97,11 @@ impl CapturePass { } => { let mut t_inputs = Vec::with_capacity(inputs.len()); for input in inputs { - t_inputs.push(Self::transform(input, capture_map)); + t_inputs.push(Rc::new(Self::transform(input.as_ref().clone(), capture_map))); } node.kind = BoundKind::Pipe { inputs: t_inputs, - lambda: Box::new(Self::transform(*lambda, capture_map)), + lambda: Rc::new(Self::transform(lambda.as_ref().clone(), capture_map)), out_type: out_type.clone(), }; } @@ -108,7 +109,7 @@ impl CapturePass { node.kind = BoundKind::Block { exprs: exprs .into_iter() - .map(|e| Self::transform(e, capture_map)) + .map(|e| Rc::new(Self::transform(e.as_ref().clone(), capture_map))) .collect(), }; } @@ -117,7 +118,7 @@ impl CapturePass { node.kind = BoundKind::Tuple { elements: elements .into_iter() - .map(|e| Self::transform(e, capture_map)) + .map(|e| Rc::new(Self::transform(e.as_ref().clone(), capture_map))) .collect(), }; } @@ -127,7 +128,7 @@ impl CapturePass { layout, values: values .into_iter() - .map(|v| Self::transform(v, capture_map)) + .map(|v| Rc::new(Self::transform(v.as_ref().clone(), capture_map))) .collect(), }; } @@ -138,7 +139,7 @@ impl CapturePass { } => { node.kind = BoundKind::Expansion { original_call, - bound_expanded: Box::new(Self::transform(*bound_expanded, capture_map)), + bound_expanded: Rc::new(Self::transform(bound_expanded.as_ref().clone(), capture_map)), }; } diff --git a/src/ast/compiler/optimizer/engine.rs b/src/ast/compiler/optimizer/engine.rs index 006a7e4..c867444 100644 --- a/src/ast/compiler/optimizer/engine.rs +++ b/src/ast/compiler/optimizer/engine.rs @@ -55,35 +55,40 @@ impl Optimizer { return node; } - let mut current = node; + let mut current = Rc::new(node); for _ in 0..self.max_passes { let mut sub = SubstitutionMap::new(); let mut path = PathTracker::new(); let next = self.visit_node(current.clone(), &mut sub, &mut path); - if next == current { + if Rc::ptr_eq(&next, ¤t) { break; } current = next; } - current + // Unwrap the final Rc if we are at the end, or return a clone of the inner node. + // Since AnalyzedNode is small now (header + Rcs), cloning is cheap. + (*current).clone() } fn visit_node( &self, - node: AnalyzedNode, + node_rc: Rc, sub: &mut SubstitutionMap, path: &mut PathTracker, - ) -> AnalyzedNode { + ) -> Rc { + let node = &*node_rc; let folder = Folder::new(&self.globals); let inliner = Inliner::new(&self.globals, &self.global_purity); - let (new_kind, metrics) = match node.kind { - BoundKind::Get { addr, ref name } => { + + let (new_kind, metrics) = match &node.kind { + BoundKind::Get { addr, name } => { + let addr = *addr; if !sub.assigned.contains(&addr) { // 1. Try inlining from current value substitution map (locals/globals/upvalues) if let Some(val) = sub.get_value(&addr) && inliner.is_inlinable_value(val, addr) { - return folder.make_constant_node(val.clone(), &node); + return Rc::new(folder.make_constant_node(val.clone(), &node)); } // 2. Try inlining from AST substitution map (pure expressions) @@ -99,7 +104,7 @@ impl Optimizer { if let Some(val) = globals.get(idx.0 as usize) && inliner.is_inlinable_value(val, addr) { - return folder.make_constant_node(val.clone(), &node); + return Rc::new(folder.make_constant_node(val.clone(), &node)); } } } @@ -114,62 +119,71 @@ impl Optimizer { ) } - BoundKind::FieldAccessor(k) => (BoundKind::FieldAccessor(k), node.ty.clone()), + BoundKind::FieldAccessor(k) => (BoundKind::FieldAccessor(*k), node.ty.clone()), - BoundKind::GetField { ref rec, field } => { - let rec_opt = self.visit_node((**rec).clone(), sub, path); + BoundKind::GetField { rec, field } => { + let rec_opt = self.visit_node(rec.clone(), sub, path); // Constant folding for Field Access if let BoundKind::Constant(Value::Record(layout, values)) = &rec_opt.kind - && let Some(idx) = layout.index_of(field) + && let Some(idx) = layout.index_of(*field) { - return folder.make_constant_node(values[idx].clone(), &node); + return Rc::new(folder.make_constant_node(values[idx].clone(), &node)); + } + + if Rc::ptr_eq(&rec_opt, rec) { + return node_rc; } ( BoundKind::GetField { - rec: Box::new(rec_opt), - field, + rec: rec_opt, + field: *field, }, node.ty.clone(), ) } BoundKind::Set { addr, value } => { - let value = Box::new(self.visit_node(*value, sub, path)); - if let BoundKind::Constant(val) = &value.kind { - sub.add_value(addr, val.clone()); + let value_opt = self.visit_node(value.clone(), sub, path); + if let BoundKind::Constant(val) = &value_opt.kind { + sub.add_value(*addr, val.clone()); } else { - sub.remove_value(&addr); + sub.remove_value(addr); } + + if Rc::ptr_eq(&value_opt, value) { + return node_rc; + } + ( BoundKind::Set { - addr: sub.map_address(addr), - value, + addr: sub.map_address(*addr), + value: value_opt, }, node.ty.clone(), ) } BoundKind::Define { - ref name, + name, addr, kind, - ref value, - ref captured_by, + value, + captured_by, } => { - let value_opt = Box::new(self.visit_node((**value).clone(), sub, path)); + let value_opt = self.visit_node(value.clone(), sub, path); if let Address::Local(slot) = addr && !captured_by.is_empty() { - sub.captured_slots.insert(slot); + sub.captured_slots.insert(*slot); } if let BoundKind::Constant(val) = &value_opt.kind { - sub.add_value(addr, val.clone()); + sub.add_value(*addr, val.clone()); } else { - sub.remove_value(&addr); + sub.remove_value(addr); } if let Address::Global(global_index) = addr @@ -178,14 +192,18 @@ impl Optimizer { { purity_rc .borrow_mut() - .insert(global_index, value_opt.ty.purity); + .insert(*global_index, value_opt.ty.purity); + } + + if Rc::ptr_eq(&value_opt, value) { + return node_rc; } ( BoundKind::Define { name: name.clone(), - addr: sub.map_address(addr), - kind, + addr: sub.map_address(*addr), + kind: *kind, value: value_opt, captured_by: captured_by.clone(), }, @@ -194,41 +212,41 @@ impl Optimizer { } BoundKind::Call { callee, args } => { - let callee = self.visit_node(*callee, sub, path); - let args = self.visit_node(*args, sub, path); + let callee_opt = self.visit_node(callee.clone(), sub, path); + let args_opt = self.visit_node(args.clone(), sub, path); if self.enabled { // Optimized Field Access Transformation - if let BoundKind::FieldAccessor(k) = &callee.kind - && let BoundKind::Tuple { elements } = &args.kind + if let BoundKind::FieldAccessor(k) = &callee_opt.kind + && let BoundKind::Tuple { elements } = &args_opt.kind && elements.len() == 1 { let rec = elements[0].clone(); let metrics = node.ty.clone(); - return Node { - identity: node.identity, + return Rc::new(Node { + identity: node.identity.clone(), kind: BoundKind::GetField { - rec: Box::new(rec), + rec, field: *k, }, ty: metrics, - }; + }); } let mut arg_nodes = Vec::new(); - self.flatten_tuple(args.clone(), &mut arg_nodes); + self.flatten_tuple(args_opt.clone(), &mut arg_nodes); if let BoundKind::Lambda { params, body, upvalues, positional_count, - } = &callee.kind + } = &callee_opt.kind && upvalues.is_empty() && positional_count.is_some() && path.inlining_depth < 5 - && !callee.ty.is_recursive - && path.enter_lambda(&callee.identity) + && !callee_opt.ty.is_recursive + && path.enter_lambda(&callee_opt.identity) { path.inlining_depth += 1; let mut inner_sub = sub.new_inner(); @@ -236,12 +254,12 @@ impl Optimizer { .prepare_beta_reduction(params, &arg_nodes, body, &mut inner_sub) .is_some() { - Some(self.visit_node((**body).clone(), &mut inner_sub, path)) + Some(self.visit_node(body.clone(), &mut inner_sub, path)) } else { None }; path.inlining_depth -= 1; - path.exit_lambda(&callee.identity); + path.exit_lambda(&callee_opt.identity); if let Some(res) = collapsed { return res; @@ -251,7 +269,7 @@ impl Optimizer { if let BoundKind::Get { addr: Address::Global(idx), .. - } = &callee.kind + } = &callee_opt.kind && let Some(registry_rc) = &self.lambda_registry && path.inlining_depth < 5 && !path.inlining_stack.contains(idx) @@ -275,7 +293,7 @@ impl Optimizer { .prepare_beta_reduction(params, &arg_nodes, body, &mut inner_sub) .is_some() { - Some(self.visit_node((**body).clone(), &mut inner_sub, path)) + Some(self.visit_node(body.clone(), &mut inner_sub, path)) } else { None }; @@ -288,7 +306,7 @@ impl Optimizer { } } - if let BoundKind::Constant(Value::Object(ref obj)) = callee.kind + if let BoundKind::Constant(Value::Object(ref obj)) = callee_opt.kind && path.inlining_depth < 5 && let Some(closure) = obj.as_any().downcast_ref::() && (closure.upvalues.is_empty() @@ -306,7 +324,7 @@ impl Optimizer { path.inlining_depth += 1; let inlined_body = self.visit_node( - (*closure.function_node).clone(), + closure.function_node.clone(), &mut closure_sub, path, ); @@ -332,57 +350,75 @@ impl Optimizer { } } - if let Some(folded) = folder.try_fold_pure(&callee, &arg_nodes) { - return folded; + if let Some(folded) = folder.try_fold_pure(&callee_opt, &arg_nodes) { + return Rc::new(folded); } } + if Rc::ptr_eq(&callee_opt, callee) && Rc::ptr_eq(&args_opt, args) { + return node_rc; + } + ( BoundKind::Call { - callee: Box::new(callee), - args: Box::new(args), + callee: callee_opt, + args: args_opt, }, node.ty.clone(), ) } BoundKind::Again { args } => { - let args = self.visit_node(*args, sub, path); + let args_opt = self.visit_node(args.clone(), sub, path); + if Rc::ptr_eq(&args_opt, args) { + return node_rc; + } ( BoundKind::Again { - args: Box::new(args), + args: args_opt, }, node.ty.clone(), ) } BoundKind::If { - ref cond, - ref then_br, - ref else_br, + cond, + then_br, + else_br, } => { - let cond_opt = self.visit_node((**cond).clone(), sub, path); + let cond_opt = self.visit_node(cond.clone(), sub, path); if self.enabled && let BoundKind::Constant(ref val) = cond_opt.kind { if val.is_truthy() { - return self.visit_node((**then_br).clone(), sub, path); + return self.visit_node(then_br.clone(), sub, path); } else if let Some(else_node) = else_br { - return self.visit_node((**else_node).clone(), sub, path); + return self.visit_node(else_node.clone(), sub, path); } else { - return folder.make_nop_node(&node); + return Rc::new(folder.make_nop_node(&node)); } } - let then_br = Box::new(self.visit_node((**then_br).clone(), sub, path)); - let else_br = else_br + let then_br_opt = self.visit_node(then_br.clone(), sub, path); + let else_br_opt = else_br .as_ref() - .map(|e| Box::new(self.visit_node((**e).clone(), sub, path))); + .map(|e| self.visit_node(e.clone(), sub, path)); + + let unchanged = Rc::ptr_eq(&cond_opt, cond) && Rc::ptr_eq(&then_br_opt, then_br) && match (&else_br_opt, else_br) { + (Some(a), Some(b)) => Rc::ptr_eq(a, b), + (None, None) => true, + _ => false, + }; + + if unchanged { + return node_rc; + } + ( BoundKind::If { - cond: Box::new(cond_opt), - then_br, - else_br, + cond: cond_opt, + then_br: then_br_opt, + else_br: else_br_opt, }, node.ty.clone(), ) @@ -394,10 +430,20 @@ impl Optimizer { out_type, } => { let mut o_inputs = Vec::with_capacity(inputs.len()); + let mut inputs_changed = false; for input in inputs { - o_inputs.push(self.visit_node(input, sub, path)); + let opt = self.visit_node(input.clone(), sub, path); + if !Rc::ptr_eq(&opt, input) { + inputs_changed = true; + } + o_inputs.push(opt); } - let o_lambda = Box::new(self.visit_node(*lambda, sub, path)); + let o_lambda = self.visit_node(lambda.clone(), sub, path); + + if !inputs_changed && Rc::ptr_eq(&o_lambda, lambda) { + return node_rc; + } + ( BoundKind::Pipe { inputs: o_inputs, @@ -408,7 +454,7 @@ impl Optimizer { ) } - BoundKind::Block { ref exprs } => { + BoundKind::Block { exprs } => { let mut info = UsageInfo::default(); if !exprs.is_empty() { for e in exprs { @@ -420,6 +466,7 @@ impl Optimizer { let mut new_exprs = Vec::with_capacity(exprs.len()); let last_idx = exprs.len().saturating_sub(1); + let mut block_changed = false; for (i, e) in exprs.iter().enumerate() { let is_last = i == last_idx; @@ -448,20 +495,29 @@ impl Optimizer { }; if removable { + block_changed = true; continue; } } let opt = self.visit_node(e.clone(), sub, path); if self.enabled && matches!(opt.kind, BoundKind::Nop) && !is_last { + block_changed = true; continue; } + if !Rc::ptr_eq(&opt, e) { + block_changed = true; + } new_exprs.push(opt); } + if !block_changed { + return node_rc; + } + if self.enabled { if new_exprs.is_empty() { - return folder.make_nop_node(&node); + return Rc::new(folder.make_nop_node(&node)); } else if new_exprs.len() == 1 { return new_exprs.pop().unwrap(); } @@ -470,20 +526,12 @@ impl Optimizer { (BoundKind::Block { exprs: new_exprs }, node.ty.clone()) } - BoundKind::Lambda { .. } => { - let (params, original_upvalues, body, positional_count) = - if let BoundKind::Lambda { - params, - upvalues, - body, - positional_count, - } = &node.kind - { - (params, upvalues, body, positional_count) - } else { - unreachable!() - }; - + BoundKind::Lambda { + params, + upvalues, + body, + positional_count, + } => { let mut info = UsageInfo::default(); info.collect(&node); @@ -491,8 +539,9 @@ impl Optimizer { let mut mapping = Vec::new(); let mut next_inner_subs = sub.new_inner(); next_inner_subs.assigned = info.assigned; + let mut upvalues_changed = false; - for (old_idx, capture_addr) in original_upvalues.iter().enumerate() { + for (old_idx, capture_addr) in upvalues.iter().enumerate() { let mut inlined_val = None; if !sub.assigned.contains(capture_addr) && let Some(val) = sub.get_value(capture_addr) @@ -508,40 +557,45 @@ impl Optimizer { next_inner_subs .add_value(Address::Upvalue(UpvalueIdx(old_idx as u32)), val); mapping.push(None); + upvalues_changed = true; } else { mapping.push(Some(new_upvalues.len() as u32)); - new_upvalues.push(sub.map_address(*capture_addr)); + let mapped = sub.map_address(*capture_addr); + if mapped != *capture_addr { + upvalues_changed = true; + } + new_upvalues.push(mapped); } } - let params_node = - self.visit_node(params.as_ref().clone(), &mut next_inner_subs, path); - inliner.collect_parameter_slots(¶ms_node, &mut next_inner_subs); + let params_opt = self.visit_node(params.clone(), &mut next_inner_subs, path); + inliner.collect_parameter_slots(¶ms_opt, &mut next_inner_subs); - let body_node = self.visit_node(body.as_ref().clone(), &mut next_inner_subs, path); - let reindexed_body = if new_upvalues.len() != original_upvalues.len() { - sub.reindex_upvalues(body_node, &mapping) + let body_opt = self.visit_node(body.clone(), &mut next_inner_subs, path); + let reindexed_body = if new_upvalues.len() != upvalues.len() { + sub.reindex_upvalues(body_opt, &mapping) } else { - body_node + body_opt }; + if !upvalues_changed && Rc::ptr_eq(¶ms_opt, params) && Rc::ptr_eq(&reindexed_body, body) { + return node_rc; + } + ( BoundKind::Lambda { - params: Rc::new(params_node), + params: params_opt, upvalues: new_upvalues, - body: Rc::new(reindexed_body), + body: reindexed_body, positional_count: *positional_count, }, node.ty.clone(), ) } - BoundKind::Destructure { - ref pattern, - ref value, - } => { - let val_opt = Box::new(self.visit_node((**value).clone(), sub, path)); - let pat_opt = Box::new(self.visit_node((**pattern).clone(), sub, path)); + BoundKind::Destructure { pattern, value } => { + let val_opt = self.visit_node(value.clone(), sub, path); + let pat_opt = self.visit_node(pattern.clone(), sub, path); let mut info = UsageInfo::default(); info.collect_pattern(&pat_opt); @@ -549,6 +603,10 @@ impl Optimizer { sub.remove_value(&addr); } + if Rc::ptr_eq(&val_opt, value) && Rc::ptr_eq(&pat_opt, pattern) { + return node_rc; + } + ( BoundKind::Destructure { pattern: pat_opt, @@ -559,25 +617,39 @@ impl Optimizer { } BoundKind::Tuple { elements } => { - let elements = elements - .into_iter() - .map(|e| self.visit_node(e, sub, path)) - .collect(); - (BoundKind::Tuple { elements }, node.ty.clone()) + let mut new_elements = Vec::with_capacity(elements.len()); + let mut changed = false; + for e in elements { + let opt = self.visit_node(e.clone(), sub, path); + if !Rc::ptr_eq(&opt, e) { + changed = true; + } + new_elements.push(opt); + } + if !changed { + return node_rc; + } + (BoundKind::Tuple { elements: new_elements }, node.ty.clone()) } - BoundKind::Record { - ref layout, - ref values, - } => { - let mapped_values: Vec<_> = values - .iter() - .map(|v| self.visit_node(v.clone(), sub, path)) - .collect(); + BoundKind::Record { layout, values } => { + let mut mapped_values = Vec::with_capacity(values.len()); + let mut changed = false; + for v in values { + let opt = self.visit_node(v.clone(), sub, path); + if !Rc::ptr_eq(&opt, v) { + changed = true; + } + mapped_values.push(opt); + } if self.enabled && let Some(folded) = folder.try_fold_record(layout, &mapped_values, &node) { - return folded; + return Rc::new(folded); + } + + if !changed { + return node_rc; } ( @@ -589,36 +661,40 @@ impl Optimizer { ) } BoundKind::Expansion { - ref original_call, - ref bound_expanded, + original_call, + bound_expanded, } => { path.inlining_depth += 1; - let bound_expanded = - Box::new(self.visit_node((**bound_expanded).clone(), sub, path)); + let expanded_opt = self.visit_node(bound_expanded.clone(), sub, path); path.inlining_depth -= 1; + + if Rc::ptr_eq(&expanded_opt, bound_expanded) { + return node_rc; + } + ( BoundKind::Expansion { original_call: original_call.clone(), - bound_expanded, + bound_expanded: expanded_opt, }, node.ty.clone(), ) } - k => (k, node.ty.clone()), + k => (k.clone(), node.ty.clone()), }; - Node { - identity: node.identity, + Rc::new(Node { + identity: node.identity.clone(), kind: new_kind, ty: metrics, - } + }) } - fn flatten_tuple(&self, node: AnalyzedNode, into: &mut Vec) { - match node.kind { + fn flatten_tuple(&self, node: Rc, into: &mut Vec>) { + match &node.kind { BoundKind::Tuple { elements } => { for el in elements { - self.flatten_tuple(el, into); + self.flatten_tuple(el.clone(), into); } } BoundKind::Nop => {} diff --git a/src/ast/compiler/optimizer/folder.rs b/src/ast/compiler/optimizer/folder.rs index 1f3d186..2bd3631 100644 --- a/src/ast/compiler/optimizer/folder.rs +++ b/src/ast/compiler/optimizer/folder.rs @@ -51,7 +51,7 @@ impl<'a> Folder<'a> { pub fn try_fold_record( &self, layout: &std::sync::Arc, - values: &[AnalyzedNode], + values: &[Rc], template: &AnalyzedNode, ) -> Option { let mut constant_values = Vec::with_capacity(values.len()); @@ -71,7 +71,7 @@ impl<'a> Folder<'a> { pub fn try_fold_pure( &self, callee: &AnalyzedNode, - arg_nodes: &[AnalyzedNode], + arg_nodes: &[Rc], ) -> Option { if callee.ty.purity < Purity::Pure { return None; diff --git a/src/ast/compiler/optimizer/inliner.rs b/src/ast/compiler/optimizer/inliner.rs index 274cf70..8ba1ccd 100644 --- a/src/ast/compiler/optimizer/inliner.rs +++ b/src/ast/compiler/optimizer/inliner.rs @@ -65,7 +65,7 @@ impl<'a> Inliner<'a> { pub fn prepare_beta_reduction( &self, params: &AnalyzedNode, - arg_vals: &[AnalyzedNode], + arg_vals: &[Rc], body: &AnalyzedNode, sub: &mut SubstitutionMap, ) -> Option<()> { @@ -102,7 +102,7 @@ impl<'a> Inliner<'a> { pub fn map_params_to_args( &self, pattern: &AnalyzedNode, - args: &[AnalyzedNode], + args: &[Rc], offset: &mut usize, sub: &mut SubstitutionMap, body_usage: &UsageInfo, @@ -117,13 +117,13 @@ impl<'a> Inliner<'a> { } else if let BoundKind::Lambda { upvalues, .. } = &arg.kind && upvalues.is_empty() { - sub.add_ast_substitution(*addr, arg.clone()); + sub.add_ast_substitution(*addr, (**arg).clone()); } else if let BoundKind::Get { addr: Address::Global(_), .. } = &arg.kind { - sub.add_ast_substitution(*addr, arg.clone()); + sub.add_ast_substitution(*addr, (**arg).clone()); } } diff --git a/src/ast/compiler/optimizer/substitution_map.rs b/src/ast/compiler/optimizer/substitution_map.rs index e6575a7..94315ce 100644 --- a/src/ast/compiler/optimizer/substitution_map.rs +++ b/src/ast/compiler/optimizer/substitution_map.rs @@ -2,11 +2,12 @@ use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, LocalS use crate::ast::nodes::Node; use crate::ast::types::Value; use std::collections::{HashMap, HashSet}; +use std::rc::Rc; #[derive(Default)] pub struct SubstitutionMap { pub values: HashMap, - pub ast_substitutions: HashMap, + pub ast_substitutions: HashMap>, pub slot_mapping: HashMap, pub assigned: HashSet
, pub next_slot: u32, @@ -38,7 +39,7 @@ impl SubstitutionMap { } pub fn add_ast_substitution(&mut self, addr: Address, node: AnalyzedNode) { - self.ast_substitutions.insert(addr, node); + self.ast_substitutions.insert(addr, Rc::new(node)); } pub fn map_slot(&mut self, old_slot: LocalSlot) -> LocalSlot { @@ -81,12 +82,13 @@ impl SubstitutionMap { } } - pub fn reindex_upvalues(&self, node: AnalyzedNode, mapping: &[Option]) -> AnalyzedNode { - let (new_kind, metrics) = match node.kind { + pub fn reindex_upvalues(&self, node_rc: Rc, mapping: &[Option]) -> Rc { + let node = &*node_rc; + let (new_kind, metrics) = match &node.kind { BoundKind::Get { addr, name } => ( BoundKind::Get { - addr: self.reindex_addr(addr, mapping), - name, + addr: self.reindex_addr(*addr, mapping), + name: name.clone(), }, node.ty.clone(), ), @@ -98,14 +100,14 @@ impl SubstitutionMap { } => { let mut next_upvalues = Vec::new(); for addr in upvalues { - next_upvalues.push(self.reindex_addr(addr, mapping)); + next_upvalues.push(self.reindex_addr(*addr, mapping)); } ( BoundKind::Lambda { - params, + params: params.clone(), upvalues: next_upvalues, - body, - positional_count, + body: body.clone(), + positional_count: *positional_count, }, node.ty.clone(), ) @@ -115,9 +117,9 @@ impl SubstitutionMap { then_br, else_br, } => { - let cond = Box::new(self.reindex_upvalues(*cond, mapping)); - let then_br = Box::new(self.reindex_upvalues(*then_br, mapping)); - let else_br = else_br.map(|e| Box::new(self.reindex_upvalues(*e, mapping))); + let cond = self.reindex_upvalues(cond.clone(), mapping); + let then_br = self.reindex_upvalues(then_br.clone(), mapping); + let else_br = else_br.as_ref().map(|e| self.reindex_upvalues(e.clone(), mapping)); ( BoundKind::If { cond, @@ -129,14 +131,14 @@ impl SubstitutionMap { } BoundKind::Block { exprs } => { let exprs = exprs - .into_iter() - .map(|e| self.reindex_upvalues(e, mapping)) + .iter() + .map(|e| self.reindex_upvalues(e.clone(), mapping)) .collect(); (BoundKind::Block { exprs }, node.ty.clone()) } BoundKind::Call { callee, args } => { - let callee = Box::new(self.reindex_upvalues(*callee, mapping)); - let args = Box::new(self.reindex_upvalues(*args, mapping)); + let callee = self.reindex_upvalues(callee.clone(), mapping); + let args = self.reindex_upvalues(args.clone(), mapping); (BoundKind::Call { callee, args }, node.ty.clone()) } BoundKind::Define { @@ -146,42 +148,58 @@ impl SubstitutionMap { value, captured_by, } => { - let value = Box::new(self.reindex_upvalues(*value, mapping)); + let value = self.reindex_upvalues(value.clone(), mapping); ( BoundKind::Define { - name, - addr, - kind, + name: name.clone(), + addr: *addr, + kind: *kind, value, - captured_by, + captured_by: captured_by.clone(), }, node.ty.clone(), ) } BoundKind::Set { addr, value } => { - let value = Box::new(self.reindex_upvalues(*value, mapping)); - (BoundKind::Set { addr, value }, node.ty.clone()) + let value = self.reindex_upvalues(value.clone(), mapping); + ( + BoundKind::Set { + addr: *addr, + value, + }, + node.ty.clone(), + ) } BoundKind::Tuple { elements } => { let elements = elements - .into_iter() - .map(|e| self.reindex_upvalues(e, mapping)) + .iter() + .map(|e| self.reindex_upvalues(e.clone(), mapping)) .collect(); (BoundKind::Tuple { elements }, node.ty.clone()) } BoundKind::Record { layout, values } => { let values = values - .into_iter() - .map(|v| self.reindex_upvalues(v, mapping)) + .iter() + .map(|v| self.reindex_upvalues(v.clone(), mapping)) .collect(); - (BoundKind::Record { layout, values }, node.ty.clone()) + (BoundKind::Record { layout: layout.clone(), values }, node.ty.clone()) } - k => (k, node.ty.clone()), + BoundKind::Expansion { original_call, bound_expanded } => { + let bound_expanded = self.reindex_upvalues(bound_expanded.clone(), mapping); + ( + BoundKind::Expansion { + original_call: original_call.clone(), + bound_expanded, + }, + node.ty.clone(), + ) + } + k => (k.clone(), node.ty.clone()), }; - Node { + Rc::new(Node { identity: node.identity.clone(), kind: new_kind, ty: metrics, - } + }) } } diff --git a/src/ast/compiler/specializer.rs b/src/ast/compiler/specializer.rs index 88d57e0..83a27c9 100644 --- a/src/ast/compiler/specializer.rs +++ b/src/ast/compiler/specializer.rs @@ -53,13 +53,13 @@ impl Specializer { let (new_kind, metrics) = match node.kind { BoundKind::Call { callee, args } => { let (new_callee, new_args, _ret_ty) = - self.specialize_call_logic(*callee, *args, node.ty.original.ty.clone()); + self.specialize_call_logic(callee, args, node.ty.original.ty.clone()); let new_metrics = node.ty.clone(); ( BoundKind::Call { - callee: Box::new(new_callee), - args: Box::new(new_args), + callee: Rc::new(new_callee), + args: Rc::new(new_args), }, new_metrics, ) @@ -70,9 +70,9 @@ impl Specializer { then_br, else_br, } => { - let cond = Box::new(self.visit_node(*cond)); - let then_br = Box::new(self.visit_node(*then_br)); - let else_br = else_br.map(|e| Box::new(self.visit_node(*e))); + let cond = Rc::new(self.visit_node(cond.as_ref().clone())); + let then_br = Rc::new(self.visit_node(then_br.as_ref().clone())); + let else_br = else_br.map(|e| Rc::new(self.visit_node(e.as_ref().clone()))); ( BoundKind::If { cond, @@ -83,7 +83,7 @@ impl Specializer { ) } BoundKind::Block { exprs } => { - let exprs = exprs.into_iter().map(|e| self.visit_node(e)).collect(); + let exprs = exprs.into_iter().map(|e| Rc::new(self.visit_node(e.as_ref().clone()))).collect(); (BoundKind::Block { exprs }, node.ty.clone()) } BoundKind::Lambda { @@ -93,7 +93,7 @@ impl Specializer { positional_count, } => { let params = Rc::new(self.visit_node(params.as_ref().clone())); - let body = Rc::new(self.visit_node((*body).clone())); + let body = Rc::new(self.visit_node(body.as_ref().clone())); ( BoundKind::Lambda { params, @@ -111,7 +111,7 @@ impl Specializer { value, captured_by, } => { - let value = Box::new(self.visit_node(*value)); + let value = Rc::new(self.visit_node(value.as_ref().clone())); ( BoundKind::Define { name: name.clone(), @@ -124,22 +124,22 @@ impl Specializer { ) } BoundKind::Set { addr, value } => { - let value = Box::new(self.visit_node(*value)); + let value = Rc::new(self.visit_node(value.as_ref().clone())); (BoundKind::Set { addr, value }, node.ty.clone()) } BoundKind::Tuple { elements } => { - let elements = elements.into_iter().map(|e| self.visit_node(e)).collect(); + let elements = elements.into_iter().map(|e| Rc::new(self.visit_node(e.as_ref().clone()))).collect(); (BoundKind::Tuple { elements }, node.ty.clone()) } BoundKind::Record { layout, values } => { - let values = values.into_iter().map(|v| self.visit_node(v)).collect(); + let values = values.into_iter().map(|v| Rc::new(self.visit_node(v.as_ref().clone()))).collect(); (BoundKind::Record { layout, values }, node.ty.clone()) } BoundKind::Expansion { original_call, bound_expanded, } => { - let bound_expanded = Box::new(self.visit_node(*bound_expanded)); + let bound_expanded = Rc::new(self.visit_node(bound_expanded.as_ref().clone())); ( BoundKind::Expansion { original_call, @@ -160,12 +160,12 @@ impl Specializer { fn specialize_call_logic( &self, - callee: AnalyzedNode, - args: AnalyzedNode, + callee: Rc, + args: Rc, original_ty: StaticType, ) -> (AnalyzedNode, AnalyzedNode, StaticType) { - let new_callee = self.visit_node(callee); - let new_args = self.visit_node(args); + let new_callee = self.visit_node(callee.as_ref().clone()); + let new_args = self.visit_node(args.as_ref().clone()); let address = if let BoundKind::Get { addr, .. } = &new_callee.kind { *addr @@ -233,9 +233,9 @@ impl Specializer { self.cache .borrow_mut() .insert(key, (compiled_val.clone(), ret_ty.clone())); - let flat_elements = match new_args.kind { - BoundKind::Tuple { elements } => elements, - _ => vec![new_args.clone()], + let flat_elements = match &new_args.kind { + BoundKind::Tuple { elements } => elements.clone(), + _ => vec![Rc::new(new_args.clone())], }; let flat_types = flat_elements .iter() diff --git a/src/ast/compiler/tco.rs b/src/ast/compiler/tco.rs index 88e1943..b362cca 100644 --- a/src/ast/compiler/tco.rs +++ b/src/ast/compiler/tco.rs @@ -36,8 +36,8 @@ impl TCO { let node = &*node_rc; let new_kind = match &node.kind { BoundKind::Call { callee, args } => BoundKind::Call { - callee: Box::new(Self::transform(Rc::new((**callee).clone()), false)), - args: Box::new(Self::transform(Rc::new((**args).clone()), false)), + callee: Rc::new(Self::transform(callee.clone(), false)), + args: Rc::new(Self::transform(args.clone(), false)), }, BoundKind::Again { args } => { @@ -45,7 +45,7 @@ impl TCO { panic!("'again' is only allowed in tail position to avoid dead code."); } BoundKind::Again { - args: Box::new(Self::transform(Rc::new((**args).clone()), false)), + args: Rc::new(Self::transform(args.clone(), false)), } } BoundKind::Pipe { @@ -55,11 +55,11 @@ impl TCO { } => { let mut t_inputs = Vec::with_capacity(inputs.len()); for input in inputs { - t_inputs.push(Self::transform(Rc::new(input.clone()), false)); + t_inputs.push(Rc::new(Self::transform(input.clone(), false))); } BoundKind::Pipe { inputs: t_inputs, - lambda: Box::new(Self::transform(Rc::new((**lambda).clone()), false)), + lambda: Rc::new(Self::transform(lambda.clone(), false)), out_type: out_type.clone(), } } @@ -69,14 +69,14 @@ impl TCO { then_br, else_br, } => BoundKind::If { - cond: Box::new(Self::transform(Rc::new((**cond).clone()), false)), - then_br: Box::new(Self::transform( - Rc::new((**then_br).clone()), + cond: Rc::new(Self::transform(cond.clone(), false)), + then_br: Rc::new(Self::transform( + then_br.clone(), is_tail_position, )), else_br: else_br .as_ref() - .map(|e| Box::new(Self::transform(Rc::new((**e).clone()), is_tail_position))), + .map(|e| Rc::new(Self::transform(e.clone(), is_tail_position))), }, BoundKind::Block { exprs } => { @@ -88,10 +88,10 @@ impl TCO { for (i, expr) in exprs.iter().enumerate() { let is_last = i == last_idx; - new_exprs.push(Self::transform( - Rc::new(expr.clone()), + new_exprs.push(Rc::new(Self::transform( + expr.clone(), is_tail_position && is_last, - )); + ))); } BoundKind::Block { exprs: new_exprs } } @@ -111,7 +111,7 @@ impl TCO { BoundKind::Set { addr, value } => BoundKind::Set { addr: *addr, - value: Box::new(Self::transform(Rc::new((**value).clone()), false)), + value: Rc::new(Self::transform(value.clone(), false)), }, BoundKind::Define { name, @@ -123,17 +123,17 @@ impl TCO { name: name.clone(), addr: *addr, kind: *kind, - value: Box::new(Self::transform(Rc::new((**value).clone()), false)), + value: Rc::new(Self::transform(value.clone(), false)), captured_by: captured_by.clone(), }, BoundKind::Destructure { pattern, value } => BoundKind::Destructure { - pattern: Box::new(Self::transform(Rc::new((**pattern).clone()), false)), - value: Box::new(Self::transform(Rc::new((**value).clone()), false)), + pattern: Rc::new(Self::transform(pattern.clone(), false)), + value: Rc::new(Self::transform(value.clone(), false)), }, BoundKind::Record { layout, values } => { let new_values = values .iter() - .map(|v| Self::transform(Rc::new(v.clone()), false)) + .map(|v| Rc::new(Self::transform(v.clone(), false))) .collect(); BoundKind::Record { layout: layout.clone(), @@ -143,7 +143,7 @@ impl TCO { BoundKind::Tuple { elements } => { let new_elements = elements .iter() - .map(|e| Self::transform(Rc::new(e.clone()), false)) + .map(|e| Rc::new(Self::transform(e.clone(), false))) .collect(); BoundKind::Tuple { elements: new_elements, @@ -156,7 +156,7 @@ impl TCO { }, BoundKind::FieldAccessor(k) => BoundKind::FieldAccessor(*k), BoundKind::GetField { rec, field } => BoundKind::GetField { - rec: Box::new(Self::transform(Rc::new((**rec).clone()), false)), + rec: Rc::new(Self::transform(rec.clone(), false)), field: *field, }, BoundKind::Nop => BoundKind::Nop, @@ -165,8 +165,8 @@ impl TCO { bound_expanded, } => BoundKind::Expansion { original_call: original_call.clone(), - bound_expanded: Box::new(Self::transform( - Rc::new((**bound_expanded).clone()), + bound_expanded: Rc::new(Self::transform( + bound_expanded.clone(), is_tail_position, )), }, diff --git a/src/ast/compiler/type_checker.rs b/src/ast/compiler/type_checker.rs index 678eba5..a40764d 100644 --- a/src/ast/compiler/type_checker.rs +++ b/src/ast/compiler/type_checker.rs @@ -182,7 +182,7 @@ impl TypeChecker { name: name.clone(), addr: *addr, kind: *decl_kind, - value: Box::new(Node { + value: Rc::new(Node { identity: node.identity.clone(), kind: BoundKind::Nop, ty: specialized_ty.clone(), @@ -203,7 +203,7 @@ impl TypeChecker { ( BoundKind::Set { addr: *addr, - value: Box::new(Node { + value: Rc::new(Node { identity: node.identity.clone(), kind: BoundKind::Nop, ty: specialized_ty.clone(), @@ -256,7 +256,7 @@ impl TypeChecker { }; let t = self.check_params(el, &sub_ty, ctx, diag); elem_types.push(t.ty.clone()); - typed_elements.push(t); + typed_elements.push(Rc::new(t)); } ( BoundKind::Tuple { @@ -312,7 +312,7 @@ impl TypeChecker { name: name.clone(), addr: *addr, kind: *decl_kind, - value: Box::new(val_typed), + value: Rc::new(val_typed), captured_by: captured_by.clone(), }, ty, @@ -364,7 +364,7 @@ impl TypeChecker { }; ( BoundKind::GetField { - rec: Box::new(rec_typed), + rec: Rc::new(rec_typed), field: *field, }, field_ty, @@ -379,7 +379,7 @@ impl TypeChecker { ( BoundKind::Set { addr: *addr, - value: Box::new(val_typed), + value: Rc::new(val_typed), }, ty, ) @@ -391,8 +391,8 @@ impl TypeChecker { let ty = val_typed.ty.clone(); ( BoundKind::Destructure { - pattern: Box::new(pat_typed), - value: Box::new(val_typed), + pattern: Rc::new(pat_typed), + value: Rc::new(val_typed), }, ty, ) @@ -415,7 +415,7 @@ impl TypeChecker { if et.ty != final_ty { final_ty = StaticType::Any; } - else_typed = Some(Box::new(et)); + else_typed = Some(Rc::new(et)); } else { // If without else returns Optional(Then) (T | Void) final_ty = StaticType::Optional(Box::new(then_typed.ty.clone())); @@ -423,8 +423,8 @@ impl TypeChecker { ( BoundKind::If { - cond: Box::new(cond_typed), - then_br: Box::new(then_typed), + cond: Rc::new(cond_typed), + then_br: Rc::new(then_typed), else_br: else_typed, }, final_ty, @@ -443,7 +443,7 @@ impl TypeChecker { StaticType::Any }; arg_types.push(arg_ty); - typed_inputs.push(typed_input); + typed_inputs.push(Rc::new(typed_input)); } // Specialized check for the lambda using the input types! @@ -462,7 +462,7 @@ impl TypeChecker { ( BoundKind::Pipe { inputs: typed_inputs, - lambda: Box::new(typed_lambda), + lambda: Rc::new(typed_lambda), out_type: ret_ty.clone(), }, StaticType::Series(Box::new(ret_ty)), @@ -476,7 +476,7 @@ impl TypeChecker { for e in exprs { let t = self.check_node(e, ctx, diag); last_ty = t.ty.clone(); - typed_exprs.push(t); + typed_exprs.push(Rc::new(t)); } (BoundKind::Block { exprs: typed_exprs }, last_ty) @@ -539,7 +539,7 @@ impl TypeChecker { for e in elements { let t = self.check_node(e, ctx, diag); elem_types.push(t.ty.clone()); - typed_elements.push(t); + typed_elements.push(Rc::new(t)); } Node { identity: args.identity.clone(), @@ -569,8 +569,8 @@ impl TypeChecker { ( BoundKind::Call { - callee: Box::new(callee_typed), - args: Box::new(args_typed), + callee: Rc::new(callee_typed), + args: Rc::new(args_typed), }, ret_ty, ) @@ -584,7 +584,7 @@ impl TypeChecker { for e in elements { let t = self.check_node(e, ctx, diag); elem_types.push(t.ty.clone()); - typed_elements.push(t); + typed_elements.push(Rc::new(t)); } Node { identity: args.identity.clone(), @@ -611,7 +611,7 @@ impl TypeChecker { ( BoundKind::Again { - args: Box::new(args_typed), + args: Rc::new(args_typed), }, StaticType::Any, ) @@ -620,7 +620,7 @@ impl TypeChecker { BoundKind::Tuple { elements } => { let mut typed_elements = Vec::new(); for e in elements { - typed_elements.push(self.check_node(e, ctx, diag)); + typed_elements.push(Rc::new(self.check_node(e, ctx, diag))); } let ty = if typed_elements.is_empty() { @@ -663,7 +663,7 @@ impl TypeChecker { for (i, v) in values.iter().enumerate() { let vt = self.check_node(v, ctx, diag); fields_ty.push((layout.fields[i].0, vt.ty.clone())); - typed_values.push(vt); + typed_values.push(Rc::new(vt)); } let new_layout = crate::ast::types::RecordLayout::get_or_create(fields_ty); @@ -685,7 +685,7 @@ impl TypeChecker { ( BoundKind::Expansion { original_call: original_call.clone(), - bound_expanded: Box::new(expanded_typed), + bound_expanded: Rc::new(expanded_typed), }, ty, ) diff --git a/src/ast/vm.rs b/src/ast/vm.rs index 653d302..e1efb3c 100644 --- a/src/ast/vm.rs +++ b/src/ast/vm.rs @@ -893,7 +893,7 @@ impl VM { fn eval_and_flatten_internal( &mut self, obs: &mut O, - elements: &[ExecNode], + elements: &[Rc], into: &mut Vec, ) -> Result<(), String> { for e in elements {