Add positional_count field to Lambda

This field is used for static optimization, determining if parameters
are purely positional.
This commit is contained in:
Michael Schimmel
2026-02-20 14:40:56 +01:00
parent 56d6c3bbde
commit 4e812c1afb
11 changed files with 361 additions and 62 deletions
+31 -7
View File
@@ -69,10 +69,10 @@ impl Specializer {
let exprs = exprs.into_iter().map(|e| self.visit_node(e)).collect();
(BoundKind::Block { exprs }, node.ty)
},
BoundKind::Lambda { params, upvalues, body } => {
let params = Box::new(self.visit_node(*params));
BoundKind::Lambda { params, upvalues, body, positional_count } => {
let params = Rc::new(self.visit_node(params.as_ref().clone()));
let body = Rc::new(self.visit_node((*body).clone()));
(BoundKind::Lambda { params, upvalues, body }, node.ty)
(BoundKind::Lambda { params, upvalues, body, positional_count }, node.ty)
},
BoundKind::DefLocal { name, slot, value, captured_by } => {
let value = Box::new(self.visit_node(*value));
@@ -194,15 +194,25 @@ impl Specializer {
// Store in cache
self.cache.borrow_mut().insert(key, (res_val.clone(), res_ty.clone()));
// PERFORMANCE: Flatten the argument tuple to match the specialized signature.
// Since we are specializing, we can convert [[1 2] 3] into a flat [1 2 3] Tuple node.
let flat_elements = self.flatten_tuple(new_args.clone());
let flat_types = flat_elements.iter().map(|e| e.ty.clone()).collect();
let flattened_args = Node {
identity: new_args.identity.clone(),
kind: BoundKind::Tuple { elements: flat_elements },
ty: StaticType::Tuple(flat_types),
};
let specialized_callee = Node {
identity: new_callee.identity.clone(),
kind: BoundKind::Constant(res_val),
ty: StaticType::Function(Box::new(Signature {
params: StaticType::Tuple(arg_types),
params: flattened_args.ty.clone(),
ret: res_ty.clone(),
})),
};
return (specialized_callee, new_args, res_ty);
return (specialized_callee, flattened_args, res_ty);
},
Err(_) => {
// Fallback on error
@@ -214,6 +224,19 @@ impl Specializer {
// Fallback: Dynamic Call
(new_callee, new_args, original_ty)
}
fn flatten_tuple(&self, node: TypedNode) -> Vec<TypedNode> {
match node.kind {
BoundKind::Tuple { elements } => {
let mut flat = Vec::new();
for el in elements {
flat.extend(self.flatten_tuple(el));
}
flat
}
_ => vec![node],
}
}
}
#[cfg(test)]
@@ -268,7 +291,7 @@ mod tests {
let func_node = BoundNode {
identity: make_identity(),
kind: BoundKind::Lambda {
params: Box::new(BoundNode {
params: Rc::new(BoundNode {
identity: make_identity(),
kind: BoundKind::Tuple {
elements: vec![
@@ -282,7 +305,8 @@ mod tests {
ty: ()
}),
upvalues: vec![],
body: Rc::new(BoundNode { identity: make_identity(), kind: BoundKind::Nop, ty: () })
body: Rc::new(BoundNode { identity: make_identity(), kind: BoundKind::Nop, ty: () }),
positional_count: Some(1),
},
ty: ()
};