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