Refactor AST nodes to use Rc

This commit refactors various AST node types to use `Rc` (Reference
Counting) instead of `Box`. This change is primarily driven by the need
for shared ownership and more efficient handling of potentially
recursive or shared data structures within the AST.

The main benefits of this change include:

- **Reduced cloning:** `Rc` allows multiple parts of the AST to refer to
  the same node without needing to clone the entire node. This is
  particularly beneficial for optimization passes where nodes might be
  visited multiple times.
- **Enabling sharing:** It makes it easier to represent scenarios where
  a single AST node might be a child of multiple parent nodes.
- **Performance improvements:** By avoiding unnecessary deep copies of
  AST nodes, this change can lead to performance gains, especially
  during complex compilation phases.
This commit is contained in:
Michael Schimmel
2026-03-03 16:07:42 +01:00
parent 78c36cf08d
commit 7c38dee243
12 changed files with 439 additions and 336 deletions
+32 -32
View File
@@ -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,
)
+22 -22
View File
@@ -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(),
+39 -31
View File
@@ -54,7 +54,7 @@ impl<T> Clone for Box<dyn BoundExtension<T>> {
}
}
/// 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<T = ()> = Node<BoundKind<T>, T>;
/// Type alias for a node that has been fully type-checked.
@@ -91,7 +91,7 @@ pub enum BoundKind<T = ()> {
// Variable Update (Assignment)
Set {
addr: Address,
value: Box<BoundNode<T>>,
value: Rc<BoundNode<T>>,
},
// Variable Declaration (Unified for Local/Global/Parameter)
@@ -99,7 +99,7 @@ pub enum BoundKind<T = ()> {
name: Symbol,
addr: Address,
kind: DeclarationKind,
value: Box<BoundNode<T>>,
value: Rc<BoundNode<T>>,
captured_by: Vec<Identity>,
},
@@ -108,20 +108,20 @@ pub enum BoundKind<T = ()> {
/// Specialized field access (O(1) via RecordLayout)
GetField {
rec: Box<BoundNode<T>>,
rec: Rc<BoundNode<T>>,
field: crate::ast::types::Keyword,
},
If {
cond: Box<BoundNode<T>>,
then_br: Box<BoundNode<T>>,
else_br: Option<Box<BoundNode<T>>>,
cond: Rc<BoundNode<T>>,
then_br: Rc<BoundNode<T>>,
else_br: Option<Rc<BoundNode<T>>>,
},
/// A destructuring operation (can be a definition or an assignment depending on the pattern)
Destructure {
pattern: Box<BoundNode<T>>,
value: Box<BoundNode<T>>,
pattern: Rc<BoundNode<T>>,
value: Rc<BoundNode<T>>,
},
Lambda {
@@ -134,29 +134,29 @@ pub enum BoundKind<T = ()> {
},
Call {
callee: Box<BoundNode<T>>,
args: Box<BoundNode<T>>,
callee: Rc<BoundNode<T>>,
args: Rc<BoundNode<T>>,
},
Again {
args: Box<BoundNode<T>>,
args: Rc<BoundNode<T>>,
},
Pipe {
inputs: Vec<BoundNode<T>>,
lambda: Box<BoundNode<T>>,
inputs: Vec<Rc<BoundNode<T>>>,
lambda: Rc<BoundNode<T>>,
out_type: crate::ast::types::StaticType,
},
Block {
exprs: Vec<BoundNode<T>>,
exprs: Vec<Rc<BoundNode<T>>>,
},
Tuple {
elements: Vec<BoundNode<T>>,
elements: Vec<Rc<BoundNode<T>>>,
},
Record {
layout: std::sync::Arc<crate::ast::types::RecordLayout>,
values: Vec<BoundNode<T>>,
values: Vec<Rc<BoundNode<T>>>,
},
/// An expanded macro call, preserving the original call for debugging and UI.
@@ -164,7 +164,7 @@ pub enum BoundKind<T = ()> {
/// The original call from the untyped AST.
original_call: Rc<Node<crate::ast::nodes::UntypedKind>>,
/// The result of binding the expanded AST.
bound_expanded: Box<BoundNode<T>>,
bound_expanded: Rc<BoundNode<T>>,
},
/// 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,
}
}
+20 -19
View File
@@ -10,6 +10,7 @@ impl CapturePass {
}
fn transform(mut node: BoundNode, capture_map: &HashMap<Identity, Vec<Identity>>) -> 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)),
};
}
+206 -130
View File
@@ -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, &current) {
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<AnalyzedNode>,
sub: &mut SubstitutionMap,
path: &mut PathTracker,
) -> AnalyzedNode {
) -> Rc<AnalyzedNode> {
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>()
&& (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(&params_node, &mut next_inner_subs);
let params_opt = self.visit_node(params.clone(), &mut next_inner_subs, path);
inliner.collect_parameter_slots(&params_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(&params_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<AnalyzedNode>) {
match node.kind {
fn flatten_tuple(&self, node: Rc<AnalyzedNode>, into: &mut Vec<Rc<AnalyzedNode>>) {
match &node.kind {
BoundKind::Tuple { elements } => {
for el in elements {
self.flatten_tuple(el, into);
self.flatten_tuple(el.clone(), into);
}
}
BoundKind::Nop => {}
+2 -2
View File
@@ -51,7 +51,7 @@ impl<'a> Folder<'a> {
pub fn try_fold_record(
&self,
layout: &std::sync::Arc<RecordLayout>,
values: &[AnalyzedNode],
values: &[Rc<AnalyzedNode>],
template: &AnalyzedNode,
) -> Option<AnalyzedNode> {
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<AnalyzedNode>],
) -> Option<AnalyzedNode> {
if callee.ty.purity < Purity::Pure {
return None;
+4 -4
View File
@@ -65,7 +65,7 @@ impl<'a> Inliner<'a> {
pub fn prepare_beta_reduction(
&self,
params: &AnalyzedNode,
arg_vals: &[AnalyzedNode],
arg_vals: &[Rc<AnalyzedNode>],
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<AnalyzedNode>],
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());
}
}
+50 -32
View File
@@ -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<Address, Value>,
pub ast_substitutions: HashMap<Address, AnalyzedNode>,
pub ast_substitutions: HashMap<Address, Rc<AnalyzedNode>>,
pub slot_mapping: HashMap<LocalSlot, LocalSlot>,
pub assigned: HashSet<Address>,
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<u32>]) -> AnalyzedNode {
let (new_kind, metrics) = match node.kind {
pub fn reindex_upvalues(&self, node_rc: Rc<AnalyzedNode>, mapping: &[Option<u32>]) -> Rc<AnalyzedNode> {
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,
}
})
}
}
+20 -20
View File
@@ -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<AnalyzedNode>,
args: Rc<AnalyzedNode>,
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()
+21 -21
View File
@@ -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,
)),
},
+22 -22
View File
@@ -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,
)
+1 -1
View File
@@ -893,7 +893,7 @@ impl VM {
fn eval_and_flatten_internal<O: VMObserver>(
&mut self,
obs: &mut O,
elements: &[ExecNode],
elements: &[Rc<ExecNode>],
into: &mut Vec<Value>,
) -> Result<(), String> {
for e in elements {