mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
Add duplicate checking for switch on types
* Add compile error tests
This commit is contained in:
parent
78c6d39cd4
commit
0de35af98b
2 changed files with 65 additions and 1 deletions
32
src/ir.cpp
32
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue