From b2db2c54edb2f905f445ea37678af8c937031f2e Mon Sep 17 00:00:00 2001 From: agra Date: Wed, 17 Jun 2026 05:22:23 +0300 Subject: [PATCH] fix(metatype): reject duplicate variant names in define MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/ir/interp.zig | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/ir/interp.zig b/src/ir/interp.zig index 9a6f61ed..515c4df5 100644 --- a/src/ir/interp.zig +++ b/src/ir/interp.zig @@ -2129,7 +2129,18 @@ pub const Interpreter = struct { 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 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