feat(metatype): widen type_info/define to tuple types

TypeInfo gains a `tuple(TupleInfo) variant (TupleInfo{elements: []Type},
positional/unnamed) — completing the reflect/construct triad with enum
and struct.

- meta.sx: TupleInfo + `tuple TypeInfo variant.
- interp: reflectTypeInfo builds .tuple (tag 2) as bare type_tag elements
  (no name pairs); defineType dispatches tag 2 -> defineTuple, which
  decodes []Type and completes the declare slot as a structural .tuple
  via replaceKeyedInfo (kind change). Tuples are structural so the
  declared name is vestigial, but the slot is still completed in place so
  define returns the handle (consistent with enum/struct).
- call.zig: the lower-time type_info guard now admits .tuple.

define(declare("P"), .tuple(.{elements=.[i64,f64]})) builds a tuple, and
define(declare("T"), type_info((i64,bool,f64))) round-trips one. Suite
green (683).
This commit is contained in:
agra
2026-06-17 07:05:55 +03:00
parent d83f5fa90d
commit 9f3f746c4b
3 changed files with 54 additions and 7 deletions

View File

@@ -1735,11 +1735,11 @@ pub fn tryLowerReflectionCall(self: *Lowering, name: []const u8, c: *const ast.C
// inverse of `define`, which builds those kinds). A loud, well-spanned
// reject here beats a deferred interp bail; tuple widening lands later.
const reflectable = !t.isBuiltin() and switch (self.module.types.get(t)) {
.@"enum", .tagged_union, .@"struct" => true,
.@"enum", .tagged_union, .@"struct", .tuple => true,
else => false,
};
if (!reflectable) {
if (self.diagnostics) |d| d.addFmt(.err, c.args[0].span, "type_info: '{s}' is not reflectable — only enum / tagged-union / struct types reflect today", .{self.formatTypeName(t)});
if (self.diagnostics) |d| d.addFmt(.err, c.args[0].span, "type_info: '{s}' is not reflectable — only enum / tagged-union / struct / tuple types reflect today", .{self.formatTypeName(t)});
return Ref.none;
}
const type_ref = self.builder.constType(t);