ffi M5.A.next.4.0: activate Value.type_tag — opcode + helper + cmp
Wires the dormant `Value.type_tag(TypeId)` variant in interp.zig
so Type values flow through the comptime interpreter as
first-class kind-distinguished entities. No source-language
construction path yet — that's a follow-up. This commit is the
infrastructure foundation.
Audit findings (from interp.zig switch-walk):
- Every `else =>` arm over Value is either already loud
(`bailDetail` / `error.TypeError`) or a pass-through helper
(`materializeCtxArg`, `materializeForCall`, `resolveSlotChain`)
where transit-unchanged is semantically correct for type_tag.
No new silent paths introduced by activating the variant.
- The three pre-existing `.type_tag => return bailDetail(...)`
arms (store-at-raw-ptr, deref-non-pointer, unbox-non-aggregate)
already cover the disallowed paths cleanly.
New plumbing:
- `Op.const_type: TypeId` — dedicated opcode. Never piggybacks
on `const_int`. Result IR-type is `.any` to signal "untyped
at runtime" so downstream coercions fail loudly.
- `Builder.constType(tid)` constructor.
- Interp arm emits `Value{ .type_tag = tid }` for the op.
- emit_llvm arm bails loudly + emits an undef-i64 placeholder
(Type is comptime-only — if a Type ever reached LLVM emit,
some upstream builder leaked through; the diagnostic + LLVM
verifier downstream surface the offending site).
- `print.zig` arm prints `const type(<typeName>)`.
- `Value.asTypeId() ?TypeId` helper — the kind-honest accessor
for Type values. asInt/asFloat/asBool/asString continue to
return null for `.type_tag` (no silent coercion).
- `evalCmp` arm for `.type_tag, .type_tag` — TypeId equality.
Mixed `.type_tag` vs `.int` deliberately falls through to
the typeErrorDetail bail (a Type is not an int).
Tests (src/ir/interp.test.zig):
- `const_type yields type_tag` — confirms the variant is
produced and that asTypeId/asInt distinguish correctly.
- `type_tag comparison` — exercises cmp_eq on equal and
unequal pairs, asserts the right bool comes back.
208/208 example tests + `zig build test` green. No user-visible
behaviour change yet — `.type_tag` is constructible from Zig-
side IR builders but no sx-level syntax produces it. Next slice
wires `$args` lowering (or `$args[i]` in expression position)
to emit `const_type` per pack element.
This commit is contained in:
@@ -1668,6 +1668,17 @@ pub const LLVMEmitter = struct {
|
||||
self.mapRef(llvm_val);
|
||||
}
|
||||
},
|
||||
.const_type => |tid| {
|
||||
// Type values are comptime-only — they MUST be erased by
|
||||
// the time we emit LLVM. Reaching here means a Type leaked
|
||||
// into a runtime path (e.g. a builder returned a Type from
|
||||
// a fn the compiler didn't strip). Loud failure: emit an
|
||||
// undef placeholder so the verifier catches downstream
|
||||
// use, AND log the offending TypeId so the diagnostic is
|
||||
// actionable.
|
||||
std.debug.print("emit_llvm: Type value reached runtime (TypeId={}). Type is comptime-only; check the builder path that produced this.\n", .{@intFromEnum(tid)});
|
||||
self.mapRef(c.LLVMGetUndef(self.cached_i64));
|
||||
},
|
||||
|
||||
// ── Arithmetic ─────────────────────────────────────────
|
||||
.add => |bin| {
|
||||
|
||||
Reference in New Issue
Block a user