Refactor: Improve type propagation in optimizer
Refactor the `updated_metrics` function to `refreshed_metrics`. This function now clones the `NodeMetrics` if the new type is identical to the original, avoiding unnecessary allocations. Also, adjust the `Block` and `Lambda` node kinds to correctly propagate concrete types after inlining, especially when dealing with polymorphic functions. This ensures that the return types of blocks and lambdas reflect the actual computed types rather than stale type variables. This change improves type inference accuracy and prepares for more advanced optimizations by ensuring type information is correctly propagated through the AST.
This commit is contained in:
@@ -2,7 +2,7 @@ use crate::ast::nodes::{
|
||||
Address, AnalyzedNode, AssignBinding, GlobalAnalyzedRegistry,
|
||||
IdentifierBinding, LambdaBinding, Node, NodeKind, NodeMetrics, UpvalueIdx, VirtualId,
|
||||
};
|
||||
use crate::ast::types::{Purity, StaticType, Value};
|
||||
use crate::ast::types::{Purity, Signature, StaticType, Value};
|
||||
use crate::ast::vm::GlobalStore;
|
||||
|
||||
use std::cell::RefCell;
|
||||
@@ -39,9 +39,12 @@ fn compute_tuple_type(elements: &[Rc<AnalyzedNode>]) -> StaticType {
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a new `NodeMetrics` with an updated `StaticType`, reusing the original
|
||||
/// node's identity, kind, and comments. Only call when the type actually changed.
|
||||
fn updated_metrics(old: &NodeMetrics, new_ty: StaticType) -> NodeMetrics {
|
||||
/// Return `NodeMetrics` with an updated `StaticType` if it differs from the
|
||||
/// original, otherwise clone cheaply. Avoids unnecessary `Rc` allocations.
|
||||
fn refreshed_metrics(old: &NodeMetrics, new_ty: StaticType) -> NodeMetrics {
|
||||
if new_ty == old.original.ty {
|
||||
return old.clone();
|
||||
}
|
||||
let orig = &old.original;
|
||||
NodeMetrics {
|
||||
original: Rc::new(Node {
|
||||
@@ -614,7 +617,9 @@ impl Optimizer {
|
||||
return node_rc;
|
||||
}
|
||||
|
||||
(NodeKind::Block { exprs: new_exprs }, node.ty.clone())
|
||||
let last_ty = new_exprs.last().map(|e| e.ty.original.ty.clone())
|
||||
.unwrap_or(StaticType::Void);
|
||||
(NodeKind::Block { exprs: new_exprs }, refreshed_metrics(&node.ty, last_ty))
|
||||
}
|
||||
|
||||
NodeKind::Lambda {
|
||||
@@ -679,6 +684,15 @@ impl Optimizer {
|
||||
return node_rc;
|
||||
}
|
||||
|
||||
let metrics = if let StaticType::Function(sig) = &node.ty.original.ty {
|
||||
refreshed_metrics(&node.ty, StaticType::Function(Box::new(Signature {
|
||||
params: sig.params.clone(),
|
||||
ret: reindexed_body.ty.original.ty.clone(),
|
||||
})))
|
||||
} else {
|
||||
node.ty.clone()
|
||||
};
|
||||
|
||||
(
|
||||
NodeKind::Lambda {
|
||||
params: params_opt,
|
||||
@@ -688,7 +702,7 @@ impl Optimizer {
|
||||
positional_count: lambda_info.positional_count,
|
||||
},
|
||||
},
|
||||
node.ty.clone(),
|
||||
metrics,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -705,12 +719,7 @@ impl Optimizer {
|
||||
if !changed {
|
||||
return node_rc;
|
||||
}
|
||||
let recomputed = compute_tuple_type(&new_elements);
|
||||
let metrics = if recomputed != node.ty.original.ty {
|
||||
updated_metrics(&node.ty, recomputed)
|
||||
} else {
|
||||
node.ty.clone()
|
||||
};
|
||||
let metrics = refreshed_metrics(&node.ty, compute_tuple_type(&new_elements));
|
||||
(NodeKind::Tuple { elements: new_elements }, metrics)
|
||||
}
|
||||
NodeKind::Record { fields, layout } => {
|
||||
|
||||
Reference in New Issue
Block a user