Monomorphize function templates by re-type-checking

Re-type-checks function templates with concrete argument types to
produce specialized TypedNodes for monomorphization. This process
leverages the `check_node_as_bound` method, which is generic enough to
handle different binding phases, allowing for fresh type inference from
the call site.
This commit is contained in:
2026-03-27 21:16:13 +01:00
parent 1379ab366a
commit ddea07666d
+11 -18
View File
@@ -705,24 +705,17 @@ impl Environment {
-> Result<(Value, StaticType), String> {
let mut diag = Diagnostics::new();
let checker = TypeChecker::new(root_types.clone());
// For specialization, we re-type-check the analyzed node.
// Note: AnalyzedNode.ty.original is the TypedNode.
// But TypeChecker expects Node<BoundPhase>. We need to go from TypedNode -> BoundNode.
// However, since TypedNode is just Node<TypedPhase>, we can't easily "un-type" it.
// Instead, we access the original AST from the binder if we had it,
// OR we make the TypeChecker generic.
// For now, we assume the TypedNode can be used where a BoundNode is expected
// if we strip the metadata.
// A better way is to store the BoundNode in NodeMetrics as well.
// Temporary fix: Re-binding from source would be too expensive.
// Let's assume for now that we can specialize directly on the TypedNode
// or that we need a small helper to transform TypedNode -> BoundNode.
// Realizing that TypedNode (StaticType) is very similar to BoundNode (()),
// we can just use the internal transform.
// Monomorphization: re-type-check the function template with the concrete
// call-site argument types, producing a specialized TypedNode.
//
// `func_template` is an AnalyzedNode whose `ty.original` holds the Rc<TypedNode>
// preserved by the Analyzer in NodeMetrics.
//
// `check_node_as_bound` is generic over all `BoundLike` phases (BoundPhase,
// TypedPhase, and AnalyzedPhase all share the same binding structure). This lets
// us re-run type inference on the TypedNode with concrete `arg_types`: existing
// `ty` metadata is discarded and all types are inferred fresh from the call site.
let retyped_ast = checker.check_node_as_bound(func_template.ty.original.as_ref(), arg_types, &mut diag);
if diag.has_errors() {