green(reify): type-fn bodies comptime-evaluated; reify fully removed from the compiler
Second slice of the re-architecture — the compiler now has ZERO type- construction code beyond declare/define. - instantiateTypeFunction: a type-fn body returning a computed Type (a call to a non-generic, bodied, Type-returning fn) is comptime-evaluated with the type bindings active, then renamed to the mangled instantiation name for identity (renameNominalType). Replaces the old reify-call pattern-matching. - DELETED: reifyType (lower/nominal.zig), findReturnReifyCall (lower/generic.zig), and the stale inline-position reify gate in resolveTypeCallWithBindings. - evalComptimeType (was evalComptimeTypeNamed): pure eval, no rename; the type-fn caller renames explicitly. renameReifiedType → renameNominalType. - The TYPE NAME now travels in the data: EnumInfo gains `name`, and define() names the slot from it (the compiler derives no name from a binding LHS). examples/0614/0615 carry `name = "..."`; RecvResult/TryResult set it too. - field_type stays a reflection #builtin (reads a type); only construction moved out. All reify mentions stripped from compiler source. examples 0614/0615/0617 run on the floor. Full suite green (673).
This commit is contained in:
@@ -1252,20 +1252,11 @@ pub fn resolveTypeCallWithBindings(self: *Lowering, cl: *const ast.Call) TypeId
|
||||
.field_access => |fa| fa.field,
|
||||
else => return .unresolved,
|
||||
};
|
||||
// Comptime type-construction builtins (REIFY). `reify` is minted in a
|
||||
// `::` type-binding position by `decl.zig` (`E :: reify(...)`); reaching it
|
||||
// HERE means an inline type position (`x : reify(...)`, a nested type arg),
|
||||
// which Phase 0 does not support — bail LOUDLY rather than fall through to
|
||||
// the misleading "unknown type 'reify'" diagnostic below.
|
||||
if (std.mem.eql(u8, callee_name, "reify")) {
|
||||
if (self.diagnostics) |d|
|
||||
d.addFmt(.err, cl.callee.span, "reify is only supported in a `::` type binding (e.g. `E :: reify(...)`) in Phase 0", .{});
|
||||
return .unresolved;
|
||||
}
|
||||
// field_type($T, i) -> Type — comptime reflection (read a type's i-th
|
||||
// field / variant-payload / element type). A genuine type-table op, kept as
|
||||
// a compiler builtin (like type_name); folds at lower time so it composes
|
||||
// inside type_eq / type_name / any type-arg slot.
|
||||
if (std.mem.eql(u8, callee_name, "field_type")) {
|
||||
// field_type($T, i) -> Type — the i-th field / variant-payload /
|
||||
// element type of `T`. Folds at lower time (it's a `$T: Type` builtin),
|
||||
// so it composes inside `type_eq` / `type_name` / any type-arg slot.
|
||||
if (cl.args.len != 2) {
|
||||
if (self.diagnostics) |d|
|
||||
d.addFmt(.err, cl.callee.span, "field_type takes a type and an index: field_type($T, i)", .{});
|
||||
@@ -1758,17 +1749,22 @@ 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);
|
||||
// A type-fn body that returns a COMPUTED Type — a call to a non-generic,
|
||||
// bodied, Type-returning fn (a comptime type constructor). Comptime-evaluate
|
||||
// the return expression with the type bindings active (so a payload `= T`
|
||||
// resolves to the bound arg) and mint under THIS instantiation's name. The
|
||||
// rename to the mangled name lets the cache check at the top return the
|
||||
// SAME TypeId on a second instantiation — `Foo(i64)` at two sites is ONE
|
||||
// type (nominal identity). Must precede the general static case below, whose
|
||||
// `resolveTypeWithBindings` can't evaluate a Type-returning call.
|
||||
if (findReturnTypeExpr(fd.body)) |ret_node| {
|
||||
if (self.returnExprMintsType(ret_node)) {
|
||||
const tid = self.evalComptimeType(ret_node) orelse return .unresolved;
|
||||
// Re-key to the instantiation's mangled (or alias) name so the
|
||||
// cache check at the top dedups a second instantiation — Contract 1.
|
||||
self.renameNominalType(tid, if (has_alias) alias_name else mangled_name);
|
||||
return tid;
|
||||
}
|
||||
}
|
||||
|
||||
// General case: the body returns a TYPE EXPRESSION that is not an inline
|
||||
@@ -1801,17 +1797,21 @@ 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;
|
||||
/// True when a type-fn's return expression mints a type at comptime — a call to
|
||||
/// a NON-generic, bodied, `Type`-returning fn (a comptime type constructor).
|
||||
/// Such a body is comptime-evaluated (its `declare`/`define` mint the type)
|
||||
/// rather than statically resolved. Excludes generic / `#builtin` type
|
||||
/// constructors (`Vector(N,T)`, `Make($T)`), which the static path handles. No
|
||||
/// hardcoded constructor names — any qualifying Type-returning fn flows here.
|
||||
pub fn returnExprMintsType(self: *Lowering, ret: *const Node) bool {
|
||||
if (ret.data != .call) return false;
|
||||
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;
|
||||
if (callee.data != .identifier) return false;
|
||||
const fd = self.program_index.fn_ast_map.get(callee.data.identifier.name) orelse return false;
|
||||
if (fd.type_params.len != 0) return false; // generic constructors stay static
|
||||
if (fd.body.data == .block and fd.body.data.block.stmts.len == 0) return false; // bodyless #builtin
|
||||
const rt = fd.return_type orelse return false;
|
||||
return rt.data == .type_expr and std.mem.eql(u8, rt.data.type_expr.name, "Type");
|
||||
}
|
||||
|
||||
/// Instantiate a tagged enum from a type function body.
|
||||
|
||||
Reference in New Issue
Block a user