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:
@@ -2477,15 +2477,12 @@ pub const Ops = struct {
|
||||
const global = self.e.reflection().getOrBuildFieldNameArray(fr.struct_type);
|
||||
const idx = self.e.resolveRef(fr.index);
|
||||
const string_ty = self.e.getStringStructType();
|
||||
// Get struct field count for array type
|
||||
const field_info = self.e.ir_mod.types.get(fr.struct_type);
|
||||
const field_count: u32 = switch (field_info) {
|
||||
.@"struct" => |s| @intCast(s.fields.len),
|
||||
.@"union" => |u| @intCast(u.fields.len),
|
||||
.tagged_union => |u| @intCast(u.fields.len),
|
||||
.@"enum" => |e| @intCast(e.variants.len),
|
||||
else => 0,
|
||||
};
|
||||
// Size the GEP's array type from the SAME single source of truth
|
||||
// (`memberCount`) that `getOrBuildFieldNameArray` uses to build the name
|
||||
// array, so the two can never disagree (a mismatch was issue 0195: the
|
||||
// array was built zero-length for tuples/arrays while this count said N →
|
||||
// an out-of-bounds GEP → segfault).
|
||||
const field_count: u32 = @intCast(self.e.ir_mod.types.memberCount(fr.struct_type) orelse 0);
|
||||
const array_ty = c.LLVMArrayType(string_ty, field_count);
|
||||
const zero = c.LLVMConstInt(self.e.cached_i64, 0, 0);
|
||||
var indices = [2]c.LLVMValueRef{ zero, idx };
|
||||
|
||||
Reference in New Issue
Block a user