fix(metatype): reject duplicate variant names in define

Two same-named variants in a constructed enum silently succeeded —
construction (.a) and matching would ambiguously pick one. defineEnum
now bails when a variant name repeats, naming it. The name is dynamic so
it sets last_bail_detail directly (bailDetail takes a comptime string);
evalComptimeType renders it as a build-gating diagnostic.
This commit is contained in:
agra
2026-06-17 05:22:23 +03:00
parent 964ddeb73a
commit b2db2c54ed

View File

@@ -2129,7 +2129,18 @@ pub const Interpreter = struct {
if (ev.len != 2) return bailDetail("comptime define(): EnumVariant must have `name` and `payload`"); if (ev.len != 2) return bailDetail("comptime define(): EnumVariant must have `name` and `payload`");
const vname = ev[0].asString(self) orelse return bailDetail("comptime define(): EnumVariant `name` is not a string"); const vname = ev[0].asString(self) orelse return bailDetail("comptime define(): EnumVariant `name` is not a string");
const payload_tid = ev[1].asTypeId() orelse return bailDetail("comptime define(): EnumVariant `payload` is not a Type value"); const payload_tid = ev[1].asTypeId() orelse return bailDetail("comptime define(): EnumVariant `payload` is not a Type value");
fields.append(self.alloc, .{ .name = tbl.internString(vname), .ty = payload_tid }) catch return error.CannotEvalComptime; const vname_id = tbl.internString(vname);
// Reject a duplicate variant name loudly — two same-named variants
// make construction (`.a`) and matching ambiguous and would silently
// pick one. The name is dynamic, so set the bail detail directly
// (bailDetail takes a comptime string); evalComptimeType renders it.
for (fields.items) |existing| {
if (existing.name == vname_id) {
last_bail_detail = std.fmt.allocPrint(self.alloc, "comptime define(): duplicate variant name '{s}'", .{vname}) catch "comptime define(): duplicate variant name";
return error.CannotEvalComptime;
}
}
fields.append(self.alloc, .{ .name = vname_id, .ty = payload_tid }) catch return error.CannotEvalComptime;
} }
// Complete the declared slot IN PLACE: it already has its name + nominal // Complete the declared slot IN PLACE: it already has its name + nominal