ffi M5.A.next.4.2: audit box_any/unbox_any/display, guard bitcast
Step 6 + 7 of the .type_tag activation plan. Audit pass on the
Any-boxing and value-display paths to confirm `.type_tag`
flows cleanly OR fails loudly.
Audit findings:
- `box_any` (interp.zig:1168) stores fields[0] as `.int(TypeId)`
for the Any-tag, fields[1] as the raw operand Value. A
`.type_tag` operand becomes the value field — correct.
Tag-field stays int-shaped across all Any boxes; value
field can be any Value kind including type_tag.
- `unbox_any` (interp.zig:1176) returns fields[1] as-is —
preserves whatever was stored. Correct for `.type_tag`.
- `any_to_string` (std.sx:316) has a `case type:` arm:
case type: { s : string = xx val; result = s; }
KNOWN GAP. Pre-`.type_tag`, the Any's value field was
string-shaped (lower-time type_name folding to const_string).
Now the value field will be `.type_tag(TypeId)`. The
`xx val to string` cast becomes a shape mismatch. Deferred
until source construction wires a path that surfaces this —
the loud bitcast guard below catches the silent-fall-through
case.
New guard:
- `bitcast` interp arm (interp.zig:664) now explicitly bails
when source is `.type_tag` and target is anything OTHER than
`.any` (boxing into Any) or the identity Type. Catches the
case-type-arm scenario above + any other stale "xx val to
string" path that would silently misinterpret a Type value.
Diagnostic suggests using `type_name(val)` as the
replacement.
No code changes in box_any / unbox_any (already correct).
208/208 example tests + `zig build test` green. No `.type_tag`
constructions exercised yet — the guards are dormant infrastructure
ready for when source construction surfaces them.
This commit is contained in:
@@ -663,6 +663,22 @@ pub const Interpreter = struct {
|
||||
},
|
||||
.bitcast => |c| {
|
||||
const val = frame.getRef(c.operand);
|
||||
// Loud-fail on `.type_tag → <runtime kind>` casts. A Type
|
||||
// value can flow through bitcast only to .any (Any-boxing)
|
||||
// or to itself; any other destination means the lowering
|
||||
// emitted a coercion that silently pretends the TypeId is
|
||||
// some other shape (e.g. an int, or a string). The most
|
||||
// likely site that would trip this: the `case type:` arm
|
||||
// of `any_to_string` in stdlib doing `xx val to string` —
|
||||
// which expects the value field to already be a string,
|
||||
// a leftover from the pre-`type_tag` era when Type values
|
||||
// were string-shaped.
|
||||
if (val == .type_tag) {
|
||||
const allowed = c.to == .any or c.to == c.from;
|
||||
if (!allowed) {
|
||||
return bailDetail("comptime bitcast: Type value cast to a non-Type runtime kind — most likely a stale `xx val to string` from the pre-type_tag era; use `type_name(val)` instead");
|
||||
}
|
||||
}
|
||||
return .{ .value = val };
|
||||
},
|
||||
.int_to_float => |c| {
|
||||
|
||||
Reference in New Issue
Block a user