Commit 0de35af98b
Changed files (2)
src
src/ir.cpp
@@ -28861,7 +28861,37 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
ir_add_error(ira, &instruction->base.base,
buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name)));
return ira->codegen->invalid_inst_gen;
- }
+ } else if(switch_type->id == ZigTypeIdMetaType) {
+ HashMap<const ZigType*, IrInstGen*, type_ptr_hash, type_ptr_eql> prevs;
+ // HashMap doubles capacity when reaching 60% capacity,
+ // because we know the size at init we can avoid reallocation by doubling it here
+ prevs.init(instruction->range_count * 2);
+ for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) {
+ IrInstSrcCheckSwitchProngsRange *range = &instruction->ranges[range_i];
+
+ IrInstGen *value = range->start->child;
+ IrInstGen *casted_value = ir_implicit_cast(ira, value, switch_type);
+ if (type_is_invalid(casted_value->value->type)) {
+ prevs.deinit();
+ return ira->codegen->invalid_inst_gen;
+ }
+
+ ZigValue *const_expr_val = ir_resolve_const(ira, casted_value, UndefBad);
+ if (!const_expr_val) {
+ prevs.deinit();
+ return ira->codegen->invalid_inst_gen;
+ }
+
+ auto entry = prevs.put_unique(const_expr_val->data.x_type, value);
+ if(entry != nullptr) {
+ ErrorMsg *msg = ir_add_error(ira, &value->base, buf_sprintf("duplicate switch value"));
+ add_error_note(ira->codegen, msg, entry->value->base.source_node, buf_sprintf("previous value is here"));
+ prevs.deinit();
+ return ira->codegen->invalid_inst_gen;
+ }
+ }
+ prevs.deinit();
+ }
return ir_const_void(ira, &instruction->base.base);
}
test/compile_errors.zig
@@ -4362,6 +4362,40 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:14: note: previous value is here",
});
+ cases.add("switch expression - duplicate type",
+ \\fn foo(comptime T: type, x: T) u8 {
+ \\ return switch (T) {
+ \\ u32 => 0,
+ \\ u64 => 1,
+ \\ u32 => 2,
+ \\ else => 3,
+ \\ };
+ \\}
+ \\export fn entry() usize { return @sizeOf(@TypeOf(foo(u32, 0))); }
+ , &[_][]const u8{
+ "tmp.zig:5:9: error: duplicate switch value",
+ "tmp.zig:3:9: note: previous value is here",
+ });
+
+ cases.add("switch expression - duplicate type (struct alias)",
+ \\const Test = struct {
+ \\ bar: i32,
+ \\};
+ \\const Test2 = Test;
+ \\fn foo(comptime T: type, x: T) u8 {
+ \\ return switch (T) {
+ \\ Test => 0,
+ \\ u64 => 1,
+ \\ Test2 => 2,
+ \\ else => 3,
+ \\ };
+ \\}
+ \\export fn entry() usize { return @sizeOf(@TypeOf(foo(u32, 0))); }
+ , &[_][]const u8{
+ "tmp.zig:9:9: error: duplicate switch value",
+ "tmp.zig:7:9: note: previous value is here",
+ });
+
cases.add("switch expression - switch on pointer type with no else",
\\fn foo(x: *u8) void {
\\ switch (x) {