green(reify): type-fn over reify memoizes by mangled name (identity)

REIFY Phase 1.1 (Phase 1 complete). instantiateTypeFunction detects a
type-fn body that returns reify(...) (findReturnReifyCall) and routes it
to reifyType under the instantiation's name — mangled for inline use,
the alias name for `Foo :: Box(i64)` — with the type-arg bindings active
so reify payloads (`payload = T`) resolve against the instantiation args.
Placed before the general case, whose resolveTypeWithBindings would
route the reify call to the inline-position loud bail.

Registering under the mangled name lets the top-of-instantiation cache
return the SAME TypeId on a second instantiation, so Box(i64) resolved
at two independent sites is ONE type (Contract 1). examples/0615 green
(build()->consume() cross-site + `b : Box(i64) = .none`). Suite green
(671 examples, 447 unit).
This commit is contained in:
agra
2026-06-16 18:54:11 +03:00
parent e4d24476a9
commit 18a4f9dd54
7 changed files with 222 additions and 10 deletions

View File

@@ -1709,6 +1709,19 @@ pub fn instantiateTypeFunction(self: *Lowering, alias_name: []const u8, template
return self.instantiateTypeUnion(if (has_alias) alias_name else mangled_name, mangled_name, &enum_decl);
}
// A type-fn body that RETURNS `reify(...)` — mint the enum under THIS
// instantiation's name (mangled for inline use, the alias name for
// `Foo :: Box(i64)`). The type-arg bindings are active here, so the reify
// payloads resolve against the instantiation's args (`payload = T` → the
// bound type). Registering under the mangled name lets the cache check at
// the top of this fn return the SAME TypeId on a second instantiation —
// so `Box(i64)` at two sites is ONE type (Contract 1). Must precede the
// general case below, whose `resolveTypeWithBindings` would route the
// reify call to the inline-position loud bail.
if (findReturnReifyCall(fd.body)) |reify_call| {
return self.reifyType(if (has_alias) alias_name else mangled_name, reify_call);
}
// General case: the body returns a TYPE EXPRESSION that is not an inline
// struct/union/enum — `return [K]T`, `Vector(K, T)`, `*T`, an alias, etc.
// Resolve it with the value/type bindings active (so `[K]T` folds K to a
@@ -1739,6 +1752,19 @@ pub fn findReturnTypeExpr(body: *const Node) ?*const Node {
return body;
}
/// The `reify(...)` call a type-fn body returns (block `return reify(...)` or
/// arrow `=> reify(...)`), or null if the body's return is not a bare `reify`
/// call. Used to route a reify-returning type-fn through `reifyType` under the
/// instantiation name (Phase 1 nominal identity).
pub fn findReturnReifyCall(body: *const Node) ?*const ast.Call {
const ret = findReturnTypeExpr(body) orelse return null;
if (ret.data != .call) return null;
const callee = ret.data.call.callee;
if (callee.data != .identifier) return null;
if (!std.mem.eql(u8, callee.data.identifier.name, "reify")) return null;
return &ret.data.call;
}
/// Instantiate a tagged enum from a type function body.
pub fn instantiateTypeUnion(self: *Lowering, alias_name: []const u8, mangled_name: []const u8, ed: *const ast.EnumDecl) ?TypeId {
const table = &self.module.types;