| author | |
| committer | |
| log | 0de35af98b3404f0cf7cd9497f661239d197bbbf |
| tree | 7aaf8bcb36debc7362e077f21ee452abd839b11e |
| parent | 78c6d39cd49225bdfd2de4da7b1730ba26a41ba4 |
* Add compile error tests2 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 | 28861 | ir_add_error(ira, &instruction->base.base, |
| 28862 | 28862 | buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name))); |
| 28863 | 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 | 28895 | return ir_const_void(ira, &instruction->base.base); |
| 28866 | 28896 | } |
| 28867 | 28897 |
test/compile_errors.zig+34| ... | ... | @@ -4362,6 +4362,40 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4362 | 4362 | "tmp.zig:5:14: note: previous value is here", |
| 4363 | 4363 | }); |
| 4364 | 4364 | |
| 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 | 4399 | cases.add("switch expression - switch on pointer type with no else", |
| 4366 | 4400 | \\fn foo(x: *u8) void { |
| 4367 | 4401 | \\ switch (x) { |