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:
agra
2026-06-16 21:03:16 +03:00
parent 442a70b8c9
commit 8ae655687a
11 changed files with 112 additions and 194 deletions

View File

@@ -186,12 +186,12 @@ pub const Interpreter = struct {
/// Comptime type-MINT target — the SAME `TypeTable` the host (`Lowering`)
/// owns (aliases `self.module.types`; the const view here and the host's
/// mutable view point at one table). Set by the host before a comptime-eval
/// that may run `declare`/`define` (the REIFY floor). Null elsewhere (unit
/// tests, emit-time `#run`) → those builtins bail loudly.
/// that may run `declare`/`define`. Null elsewhere (unit tests, emit-time
/// `#run`) → those builtins bail loudly.
mint: ?*types.TypeTable = null,
/// Monotonic suffix for `declare()`'s anonymous slot names, so two
/// undefined slots alive at once don't collide in `findByName` before the
/// binding site renames them to the real (alias / mangled) name.
/// undefined slots alive at once don't collide in `findByName` before
/// `define` names them (or a type-fn renames them to the mangled name).
declare_counter: u32 = 0,
// Heap: dynamically allocated memory blocks
@@ -257,7 +257,7 @@ pub const Interpreter = struct {
/// Enable the comptime type-construction builtins (`declare`/`define`) by
/// handing the interp the host's mutable `TypeTable`. Called by `Lowering`
/// before a comptime-eval that may mint types (the REIFY floor).
/// before a comptime-eval that may mint types.
pub fn setMintTable(self: *Interpreter, tbl: *types.TypeTable) void {
self.mint = tbl;
}
@@ -1976,7 +1976,7 @@ pub const Interpreter = struct {
return bailDetail("comptime has_impl: interp-time evaluation not yet wired (use static type args for now — they fold at lower time)");
},
// ── Comptime type CONSTRUCTION (REIFY floor) ─────────
// ── Comptime type CONSTRUCTION primitives ────────────
.declare => {
const tbl = self.mint orelse
return bailDetail("comptime declare(): no type-mint target (declare/define are comptime-only — reached at runtime/emit?)");
@@ -2027,8 +2027,11 @@ pub const Interpreter = struct {
.aggregate => |f| f,
else => return bailDetail("comptime define(): `.enum` payload is not an EnumInfo struct value"),
};
if (einfo_fields.len < 1) return bailDetail("comptime define(): EnumInfo is missing its `variants` field");
const elems = decodeVariantElements(einfo_fields[0]) orelse
// EnumInfo = `{ name: string, variants: []EnumVariant }`. The name
// travels with the shape — `define` names the slot from it.
if (einfo_fields.len != 2) return bailDetail("comptime define(): EnumInfo must have `name` and `variants`");
const name = einfo_fields[0].asString(self) orelse return bailDetail("comptime define(): EnumInfo `name` is not a string");
const elems = decodeVariantElements(einfo_fields[1]) orelse
return bailDetail("comptime define(): `variants` is not a slice/array of EnumVariant");
if (elems.len == 0) return bailDetail("comptime define(): enum has no variants");
@@ -2039,23 +2042,26 @@ pub const Interpreter = struct {
else => return bailDetail("comptime define(): EnumVariant did not evaluate to a struct value"),
};
if (ev.len != 2) return bailDetail("comptime define(): EnumVariant must have `name` and `payload`");
const name = ev[0].asString(self) orelse return bailDetail("comptime define(): EnumVariant `name` is not a string");
const vname = ev[0].asString(self) orelse return bailDetail("comptime define(): EnumVariant `name` is not a string");
const payload_tid = ev[1].asTypeId() orelse return bailDetail("comptime define(): EnumVariant `payload` is not a Type value");
fields.append(self.alloc, .{ .name = tbl.internString(name), .ty = payload_tid }) catch return error.CannotEvalComptime;
fields.append(self.alloc, .{ .name = tbl.internString(vname), .ty = payload_tid }) catch return error.CannotEvalComptime;
}
// Preserve the declared slot's intern key (name + nominal id); fill body.
// Complete the declared slot: NAME it from the EnumInfo (the name travels
// with the shape) and fill the body. The name changes the intern key
// (declare minted an anonymous `__reified_N`), so re-key via
// `replaceKeyedInfo`. The nominal id is preserved.
const cur = tbl.get(handle);
if (cur != .tagged_union) return bailDetail("comptime define(): handle is not a declare()'d enum slot");
const full: types.TypeInfo = .{ .tagged_union = .{
.name = cur.tagged_union.name,
.name = tbl.internString(name),
.fields = fields.items,
.tag_type = .i64,
.backing_type = null,
.explicit_tag_values = null,
.nominal_id = cur.tagged_union.nominal_id,
} };
tbl.updatePreservingKey(handle, full);
tbl.replaceKeyedInfo(handle, full);
return .{ .value = .void_val };
}
};