fix: comptime field reflection on tuples/arrays/vectors (issue 0195)
`field_count` / `field_name` were broken on every non-struct/enum aggregate: `field_count(Tuple(i64, bool))` silently returned 0 (a missing `.tuple` arm in the count switches), and `field_name(tuple/array/vector, i)` SEGFAULTED — the LLVM backend built a zero-length `[0 x string]` name array for those kinds while sizing the runtime GEP at the (often non-zero) member count, so the indexed load ran past the array. Root cause was three+ parallel switches that each had to know how to count an aggregate's members, and disagreed: `field_count` lowering and `memberCount` had struct/union/tagged_union/enum/array/vector but no `.tuple`; the backend's `field_name_get` build + GEP sizing had neither `.tuple` nor `.array`/`.vector`. Fix: - add the `.tuple` arm to `field_count` lowering (src/ir/lower/call.zig) and `TypeTable.memberCount` (src/ir/types.zig; this also backs the COMPILER-API `type_field_count` VM reader). - unify the LLVM backend onto the single source of truth: both `getOrBuildFieldNameArray` (reflection.zig) and `emitFieldNameGet`'s GEP sizing (ops.zig) now derive from `memberCount` / `memberName`, so the name-array length and the GEP array type can never diverge again — for any kind. A member with no name (positional-tuple / array / vector element) reflects as "" (one slot per member, always in-bounds); named-tuple elements recover their labels. The array/vector clone was surfaced by adversarial review of the tuple-only fix. Regression: examples/comptime/0646-comptime-field-reflect-tuple-array.sx exercises field_count/field_name/field_type over struct, enum, positional + named tuple, array, and vector. Full suite green (818/0). Unblocks the `race` synthesis, which must reflect a named tuple's labels + element types.
This commit is contained in:
47
examples/comptime/0646-comptime-field-reflect-tuple-array.sx
Normal file
47
examples/comptime/0646-comptime-field-reflect-tuple-array.sx
Normal file
@@ -0,0 +1,47 @@
|
||||
// Comptime field reflection (`field_count` / `field_name` / `field_type`) over
|
||||
// ALL aggregate kinds — struct, enum, tuple (positional + named), array, vector.
|
||||
//
|
||||
// Regression (issue 0195): `field_count` / `field_name` were broken on tuples
|
||||
// and arrays/vectors. `field_count` silently returned 0 (a missing `.tuple` arm
|
||||
// in the count switches), and `field_name` SEGFAULTED — the LLVM backend built a
|
||||
// zero-length name array for those kinds while sizing the GEP at the (sometimes
|
||||
// non-zero) count, so `field_name(T, i)` indexed past a `[0 x string]` global.
|
||||
// Fixed by driving BOTH the name-array build and the GEP sizing from the one
|
||||
// source of truth (`memberCount`/`memberName`), so they can never diverge again.
|
||||
// A member with no name (positional-tuple / array / vector element) reflects as
|
||||
// the empty string "" — one slot per member, always in-bounds.
|
||||
#import "modules/std.sx";
|
||||
|
||||
S :: struct { a: i64; b: bool; }
|
||||
E :: enum { X; Y; Z; }
|
||||
|
||||
main :: () -> i32 {
|
||||
// struct: named fields
|
||||
print("struct: fc={} fn=({},{}) ft0={}\n",
|
||||
field_count(S), field_name(S, 0), field_name(S, 1), type_name(field_type(S, 0)));
|
||||
|
||||
// enum: variant names
|
||||
print("enum: fc={} fn=({},{},{})\n",
|
||||
field_count(E), field_name(E, 0), field_name(E, 1), field_name(E, 2));
|
||||
|
||||
// positional tuple: element types, no names → ""
|
||||
print("postuple: fc={} ft=({},{}) fn0=[{}]\n",
|
||||
field_count(Tuple(i64, bool)),
|
||||
type_name(field_type(Tuple(i64, bool), 0)), type_name(field_type(Tuple(i64, bool), 1)),
|
||||
field_name(Tuple(i64, bool), 0));
|
||||
|
||||
// named tuple: element labels recovered
|
||||
print("namtuple: fc={} fn=({},{})\n",
|
||||
field_count(Tuple(a: i64, b: bool)),
|
||||
field_name(Tuple(a: i64, b: bool), 0), field_name(Tuple(a: i64, b: bool), 1));
|
||||
|
||||
// array: length-many elements, type known, no names → ""
|
||||
print("array: fc={} ft0={} fn0=[{}]\n",
|
||||
field_count([4]i64), type_name(field_type([4]i64, 0)), field_name([4]i64, 0));
|
||||
|
||||
// vector: same shape as array
|
||||
print("vector: fc={} ft0={} fn0=[{}]\n",
|
||||
field_count(Vector(4, f32)), type_name(field_type(Vector(4, f32), 0)), field_name(Vector(4, f32), 0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
struct: fc=2 fn=(a,b) ft0=i64
|
||||
enum: fc=3 fn=(X,Y,Z)
|
||||
postuple: fc=2 ft=(i64,bool) fn0=[]
|
||||
namtuple: fc=2 fn=(a,b)
|
||||
array: fc=4 ft0=i64 fn0=[]
|
||||
vector: fc=4 ft0=f32 fn0=[]
|
||||
Reference in New Issue
Block a user