Refactor Call to include is_tail flag

The `TailCall` variant has been merged into `Call` by adding an
`is_tail` boolean field. This simplifies the AST by reducing the number
of node variants and makes it easier to handle tail call optimization.
The `tco.rs` module is responsible for setting this flag when a call
occurs in tail position.
This commit is contained in:
Michael Schimmel
2026-02-21 21:12:20 +01:00
parent f980d9befc
commit 78dff07930
9 changed files with 41 additions and 109 deletions
+8 -8
View File
@@ -34,7 +34,7 @@ impl Optimizer {
fn visit_node(&self, node: TypedNode) -> TypedNode {
let (new_kind, new_ty) = match node.kind {
BoundKind::Call { callee, args } | BoundKind::TailCall { callee, args } => {
BoundKind::Call { callee, args, is_tail } => {
let callee = self.visit_node(*callee);
let args = self.visit_node(*args);
@@ -87,12 +87,12 @@ impl Optimizer {
};
return Node {
identity: node.identity,
kind: BoundKind::Call { callee: Box::new(cracked_lambda), args: Box::new(args) },
kind: BoundKind::Call { callee: Box::new(cracked_lambda), args: Box::new(args), is_tail },
ty: node.ty,
};
}
(BoundKind::Call { callee: Box::new(callee), args: Box::new(args) }, node.ty)
(BoundKind::Call { callee: Box::new(callee), args: Box::new(args), is_tail }, node.ty)
},
BoundKind::If { cond, then_br, else_br } => {
@@ -269,7 +269,7 @@ impl Optimizer {
self.contains_def_local(cond) || self.contains_def_local(then_br) || else_br.as_ref().is_some_and(|e| self.contains_def_local(e))
}
BoundKind::Block { exprs } => exprs.iter().any(|e| self.contains_def_local(e)),
BoundKind::Call { callee, args } | BoundKind::TailCall { callee, args } => self.contains_def_local(callee) || self.contains_def_local(args),
BoundKind::Call { callee, args, .. } => self.contains_def_local(callee) || self.contains_def_local(args),
BoundKind::Lambda { .. } => false, // Nested lambda definitions are safe (they have their own frame)
BoundKind::Tuple { elements } => elements.iter().any(|e| self.contains_def_local(e)),
BoundKind::Record { fields } => fields.iter().any(|(k, v)| self.contains_def_local(k) || self.contains_def_local(v)),
@@ -388,10 +388,10 @@ impl SubstitutionMap {
let exprs = exprs.into_iter().map(|e| self.inline_recursive(e, depth, upvalue_subs)).collect();
(BoundKind::Block { exprs }, node.ty)
},
BoundKind::Call { callee, args } | BoundKind::TailCall { callee, args } => {
BoundKind::Call { callee, args, is_tail } => {
let callee = Box::new(self.inline_recursive(*callee, depth, upvalue_subs));
let args = Box::new(self.inline_recursive(*args, depth, upvalue_subs));
(BoundKind::Call { callee, args }, node.ty)
(BoundKind::Call { callee, args, is_tail }, node.ty)
},
BoundKind::DefLocal { name, slot, value, captured_by } => {
let value = Box::new(self.inline_recursive(*value, depth, upvalue_subs));
@@ -444,10 +444,10 @@ impl SubstitutionMap {
let exprs = exprs.into_iter().map(|e| self.reindex_upvalues(e, mapping)).collect();
(BoundKind::Block { exprs }, node.ty)
},
BoundKind::Call { callee, args } | BoundKind::TailCall { callee, args } => {
BoundKind::Call { callee, args, is_tail } => {
let callee = Box::new(self.reindex_upvalues(*callee, mapping));
let args = Box::new(self.reindex_upvalues(*args, mapping));
(BoundKind::Call { callee, args }, node.ty)
(BoundKind::Call { callee, args, is_tail }, node.ty)
},
BoundKind::DefLocal { name, slot, value, captured_by } => {
let value = Box::new(self.reindex_upvalues(*value, mapping));