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
+10 -42
View File
@@ -188,48 +188,7 @@ macro_rules! dispatch_eval {
Ok(Value::Object(Rc::new(closure)))
},
BoundKind::TailCall { callee, args } => {
let func_val = $self.$eval_method($($observer,)? callee)?;
let arg_vals = match &args.kind {
BoundKind::Tuple { elements } => {
// FAST-PATH: If it's a flat tuple, evaluate directly into Vec
let mut vals = Vec::with_capacity(elements.len());
let mut is_complex = false;
for e in elements {
if matches!(e.kind, BoundKind::Tuple { .. }) {
is_complex = true;
break;
}
vals.push($self.$eval_method($($observer,)? e)?);
}
if is_complex {
macro_rules! get_args {
($s:ident, $a:ident) => { $s.prepare_args($a)? };
($s:ident, $o:ident, $a:ident) => { $s.prepare_args_observed($o, $a)? };
}
get_args!($self, $($observer,)? args)
} else {
vals
}
}
_ => {
macro_rules! get_args {
($s:ident, $a:ident) => { $s.prepare_args($a)? };
($s:ident, $o:ident, $a:ident) => { $s.prepare_args_observed($o, $a)? };
}
get_args!($self, $($observer,)? args)
}
};
match func_val {
Value::Object(obj) => Ok(Value::TailCallRequest(Box::new((obj, arg_vals)))),
Value::Function(f) => Ok(f(arg_vals)),
_ => Err(format!("Tail call target is not a function: {}", func_val)),
}
},
BoundKind::Call { callee, args } => {
BoundKind::Call { callee, args, is_tail } => {
let mut func_val = $self.$eval_method($($observer,)? callee)?;
let mut arg_vals = match &args.kind {
@@ -262,6 +221,14 @@ macro_rules! dispatch_eval {
}
};
if *is_tail {
match func_val {
Value::Object(obj) => return Ok(Value::TailCallRequest(Box::new((obj, arg_vals)))),
Value::Function(f) => return Ok(f(arg_vals)),
_ => return Err(format!("Tail call target is not a function: {}", func_val)),
}
}
loop {
match func_val {
Value::Function(f) => break Ok(f(arg_vals)),
@@ -792,6 +759,7 @@ mod tests {
ty: StaticType::Tuple(vec![]),
kind: BoundKind::Tuple { elements: vec![] },
}),
is_tail: false,
},
},
// return x (Local 0)