comptime VM: flip Type to .type_value; migrate the .any refs that mean a Type value
type_resolver "Type" -> .type_value; const_type result + emitConstType now a bare 8-byte i64 handle (not a 16-byte Any box). Migrated every .any ref meaning "a Type value", leaving real boxed-Any refs: - "Any holds a Type" meta-marker tag .any -> .type_value at all 4 consumers (reflectArgTypeId, reflectTypeId, the comptime type_tag-as-struct path, resolveTypeCategoryTags "type"). - reflection-builtin return types (type_of/declare/define) -> .type_value; runtime type_of(any) reads the tag as a .type_value (no re-box). - expr_typer: a bare type-name expr is .type_value (backtick is_raw exempt). - reflectionArgIsType accepts .type_value OR .any (a reflection arg can be a bare Type or a boxed Any). - comptime switch_br accepts a .type_tag discriminant (type-category match). - a bare function name in a Type slot -> const_type(its function type), not a func-ref (fixes a JIT crash); old string-box kept only for genuine Any params. - field-not-found diagnostic + formatTypeName render .type_value as "Type". Fixed 3 unit tests asserting the old .any behavior. 697/0 both gates (gate ON bails cleanly to legacy since the VM doesn't model Type values yet) + 494 unit tests. 24 snapshots regenerated (22 .ir const_type shape; 2 .stderr Any->Type).
This commit is contained in:
@@ -107,7 +107,7 @@ pub const Value = union(enum) {
|
||||
const fields = self.aggregate;
|
||||
if (fields.len >= 2) {
|
||||
const tag = fields[0].asInt() orelse return null;
|
||||
if (tag == @as(i64, @intCast(TypeId.any.index()))) {
|
||||
if (tag == @as(i64, @intCast(TypeId.type_value.index()))) {
|
||||
if (fields[1].asTypeId()) |t| return t;
|
||||
if (fields[1].asInt()) |iv| return TypeId.fromIndex(@intCast(iv));
|
||||
return null;
|
||||
@@ -927,7 +927,16 @@ pub const Interpreter = struct {
|
||||
switch (base) {
|
||||
.aggregate => |fields| {
|
||||
if (fa.field_index >= fields.len) return error.OutOfBounds;
|
||||
return .{ .value = fields[fa.field_index] };
|
||||
const field_val = fields[fa.field_index];
|
||||
// `type_of(an_any)` lowers to `struct_get(any, 0, .type_value)`:
|
||||
// the Any's field 0 is the held value's type id (a plain
|
||||
// `.int`), but the SSA result type is `.type_value`, so yield a
|
||||
// first-class `.type_tag` Value (a `.type_value`-typed value is
|
||||
// always a `.type_tag` in the interp — mirrors `const_type`).
|
||||
if (instruction.ty == .type_value) {
|
||||
if (field_val.asInt()) |iv| return .{ .value = .{ .type_tag = TypeId.fromIndex(@intCast(iv)) } };
|
||||
}
|
||||
return .{ .value = field_val };
|
||||
},
|
||||
.string => |s| {
|
||||
// String as fat pointer: field 0 = ptr (string), field 1 = len
|
||||
@@ -942,12 +951,12 @@ pub const Interpreter = struct {
|
||||
},
|
||||
.type_tag => |tid| {
|
||||
// A first-class Type value is the comptime form of the
|
||||
// runtime Any-Type aggregate `{ tag=.any, value=tid }`
|
||||
// runtime Any-Type aggregate `{ tag=.type_value, value=tid }`
|
||||
// (see `const_type` lowering in buildPackSliceValue).
|
||||
// `type_of(any_holding_a_Type)` lowers to struct_get
|
||||
// field 0, expecting that runtime layout — mirror it so
|
||||
// field 0 reads the `.any` tag and field 1 the type id.
|
||||
if (fa.field_index == 0) return .{ .value = .{ .int = @intCast(TypeId.any.index()) } };
|
||||
// field 0 reads the `.type_value` tag and field 1 the type id.
|
||||
if (fa.field_index == 0) return .{ .value = .{ .int = @intCast(TypeId.type_value.index()) } };
|
||||
if (fa.field_index == 1) return .{ .value = .{ .type_tag = tid } };
|
||||
return error.OutOfBounds;
|
||||
},
|
||||
@@ -1080,7 +1089,12 @@ pub const Interpreter = struct {
|
||||
return .branch;
|
||||
},
|
||||
.switch_br => |sb| {
|
||||
const operand = frame.getRef(sb.operand).asInt() orelse return error.TypeError;
|
||||
// A type-category match (`type_of(x) == { case int: … }`)
|
||||
// switches on a Type value — a `.type_tag` Value whose discriminant
|
||||
// is its TypeId index; an enum/error switch uses a plain int.
|
||||
const sb_val = frame.getRef(sb.operand);
|
||||
const operand = sb_val.asInt() orelse
|
||||
(if (sb_val.asTypeId()) |t| @as(i64, @intCast(t.index())) else return error.TypeError);
|
||||
for (sb.cases) |case| {
|
||||
if (operand == case.value) {
|
||||
const args = self.alloc.alloc(Value, case.args.len) catch return error.CannotEvalComptime;
|
||||
|
||||
Reference in New Issue
Block a user