authorgravatar for liljaanton2001@gmail.comantlilja <liljaanton2001@gmail.com> 2020-06-22 12:14:52+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-23 15:17:04-04:00
log0de35af98b3404f0cf7cd9497f661239d197bbbf
tree7aaf8bcb36debc7362e077f21ee452abd839b11e
parent78c6d39cd49225bdfd2de4da7b1730ba26a41ba4

Add duplicate checking for switch on types

* Add compile error tests

2 files changed, 65 insertions(+), 1 deletions(-)

src/ir.cpp+31-1
...@@ -28861,7 +28861,37 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,...@@ -28861,7 +28861,37 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
28861 ir_add_error(ira, &instruction->base.base,28861 ir_add_error(ira, &instruction->base.base,
28862 buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name)));28862 buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name)));
28863 return ira->codegen->invalid_inst_gen;28863 return ira->codegen->invalid_inst_gen;
28864 }28864 } else if(switch_type->id == ZigTypeIdMetaType) {
28865 HashMap<const ZigType*, IrInstGen*, type_ptr_hash, type_ptr_eql> prevs;
28866 // HashMap doubles capacity when reaching 60% capacity,
28867 // because we know the size at init we can avoid reallocation by doubling it here
28868 prevs.init(instruction->range_count * 2);
28869 for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) {
28870 IrInstSrcCheckSwitchProngsRange *range = &instruction->ranges[range_i];
28871
28872 IrInstGen *value = range->start->child;
28873 IrInstGen *casted_value = ir_implicit_cast(ira, value, switch_type);
28874 if (type_is_invalid(casted_value->value->type)) {
28875 prevs.deinit();
28876 return ira->codegen->invalid_inst_gen;
28877 }
28878
28879 ZigValue *const_expr_val = ir_resolve_const(ira, casted_value, UndefBad);
28880 if (!const_expr_val) {
28881 prevs.deinit();
28882 return ira->codegen->invalid_inst_gen;
28883 }
28884
28885 auto entry = prevs.put_unique(const_expr_val->data.x_type, value);
28886 if(entry != nullptr) {
28887 ErrorMsg *msg = ir_add_error(ira, &value->base, buf_sprintf("duplicate switch value"));
28888 add_error_note(ira->codegen, msg, entry->value->base.source_node, buf_sprintf("previous value is here"));
28889 prevs.deinit();
28890 return ira->codegen->invalid_inst_gen;
28891 }
28892 }
28893 prevs.deinit();
28894 }
28865 return ir_const_void(ira, &instruction->base.base);28895 return ir_const_void(ira, &instruction->base.base);
28866}28896}
2886728897
test/compile_errors.zig+34
...@@ -4362,6 +4362,40 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4362,6 +4362,40 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4362 "tmp.zig:5:14: note: previous value is here",4362 "tmp.zig:5:14: note: previous value is here",
4363 });4363 });
43644364
4365 cases.add("switch expression - duplicate type",
4366 \\fn foo(comptime T: type, x: T) u8 {
4367 \\ return switch (T) {
4368 \\ u32 => 0,
4369 \\ u64 => 1,
4370 \\ u32 => 2,
4371 \\ else => 3,
4372 \\ };
4373 \\}
4374 \\export fn entry() usize { return @sizeOf(@TypeOf(foo(u32, 0))); }
4375 , &[_][]const u8{
4376 "tmp.zig:5:9: error: duplicate switch value",
4377 "tmp.zig:3:9: note: previous value is here",
4378 });
4379
4380 cases.add("switch expression - duplicate type (struct alias)",
4381 \\const Test = struct {
4382 \\ bar: i32,
4383 \\};
4384 \\const Test2 = Test;
4385 \\fn foo(comptime T: type, x: T) u8 {
4386 \\ return switch (T) {
4387 \\ Test => 0,
4388 \\ u64 => 1,
4389 \\ Test2 => 2,
4390 \\ else => 3,
4391 \\ };
4392 \\}
4393 \\export fn entry() usize { return @sizeOf(@TypeOf(foo(u32, 0))); }
4394 , &[_][]const u8{
4395 "tmp.zig:9:9: error: duplicate switch value",
4396 "tmp.zig:7:9: note: previous value is here",
4397 });
4398
4365 cases.add("switch expression - switch on pointer type with no else",4399 cases.add("switch expression - switch on pointer type with no else",
4366 \\fn foo(x: *u8) void {4400 \\fn foo(x: *u8) void {
4367 \\ switch (x) {4401 \\ switch (x) {