| author | |
| committer | |
| log | e7bf8f3f04efc280a76a3a38b4e6d470d279e41a |
| tree | 2e2398667f04fa46d5de7ae4e686fe1088bf264b |
| parent | 1fb308ceeea0259ad021d67945ea5adc10960a85 |
4 files changed, 38 insertions(+), 19 deletions(-)
src/ir.cpp+12-6| ... | ... | @@ -15663,13 +15663,19 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira |
| 15663 | 15663 | field_prev_uses[start_index] = start_value->source_node; |
| 15664 | 15664 | } |
| 15665 | 15665 | if (!instruction->have_else_prong) { |
| 15666 | for (uint32_t i = 0; i < switch_type->data.error_set.err_count; i += 1) { | |
| 15667 | ErrorTableEntry *err_entry = switch_type->data.error_set.errors[i]; | |
| 15666 | if (type_is_global_error_set(switch_type)) { | |
| 15667 | ir_add_error(ira, &instruction->base, | |
| 15668 | buf_sprintf("else prong required when switching on type 'error'")); | |
| 15669 | return ira->codegen->builtin_types.entry_invalid; | |
| 15670 | } else { | |
| 15671 | for (uint32_t i = 0; i < switch_type->data.error_set.err_count; i += 1) { | |
| 15672 | ErrorTableEntry *err_entry = switch_type->data.error_set.errors[i]; | |
| 15668 | 15673 | |
| 15669 | AstNode *prev_node = field_prev_uses[err_entry->value]; | |
| 15670 | if (prev_node == nullptr) { | |
| 15671 | ir_add_error(ira, &instruction->base, | |
| 15672 | buf_sprintf("error.%s not handled in switch", buf_ptr(&err_entry->name))); | |
| 15674 | AstNode *prev_node = field_prev_uses[err_entry->value]; | |
| 15675 | if (prev_node == nullptr) { | |
| 15676 | ir_add_error(ira, &instruction->base, | |
| 15677 | buf_sprintf("error.%s not handled in switch", buf_ptr(&err_entry->name))); | |
| 15678 | } | |
| 15673 | 15679 | } |
| 15674 | 15680 | } |
| 15675 | 15681 | } |
std/io.zig+1-1| ... | ... | @@ -499,7 +499,7 @@ pub fn OutStream(comptime Error: type) type { |
| 499 | 499 | writeFn: fn(self: &Self, bytes: []const u8) Error!void, |
| 500 | 500 | |
| 501 | 501 | pub fn print(self: &Self, comptime format: []const u8, args: ...) !void { |
| 502 | return std.fmt.format(self, error, self.writeFn, format, args); | |
| 502 | return std.fmt.format(self, Error, self.writeFn, format, args); | |
| 503 | 503 | } |
| 504 | 504 | |
| 505 | 505 | pub fn write(self: &Self, bytes: []const u8) !void { |
std/zig/parser.zig+13-12| ... | ... | @@ -133,7 +133,6 @@ pub const Parser = struct { |
| 133 | 133 | Token.Id.Eof => return Tree {.root_node = root_node}, |
| 134 | 134 | else => { |
| 135 | 135 | self.putBackToken(token); |
| 136 | // TODO shouldn't need this cast | |
| 137 | 136 | stack.append(State { .TopLevelExtern = null }) catch unreachable; |
| 138 | 137 | continue; |
| 139 | 138 | }, |
| ... | ... | @@ -707,7 +706,7 @@ pub const Parser = struct { |
| 707 | 706 | return node; |
| 708 | 707 | } |
| 709 | 708 | |
| 710 | fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) error { | |
| 709 | fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) { | |
| 711 | 710 | const loc = self.tokenizer.getTokenLocation(token); |
| 712 | 711 | warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args); |
| 713 | 712 | warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]); |
| ... | ... | @@ -1082,16 +1081,18 @@ fn testCanonical(source: []const u8) !void { |
| 1082 | 1081 | var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index); |
| 1083 | 1082 | if (testParse(source, &failing_allocator.allocator)) |_| { |
| 1084 | 1083 | return error.NondeterministicMemoryUsage; |
| 1085 | } else |err| { | |
| 1086 | assert(err == error.OutOfMemory); | |
| 1087 | // TODO make this pass | |
| 1088 | //if (failing_allocator.allocated_bytes != failing_allocator.freed_bytes) { | |
| 1089 | // warn("\nfail_index: {}/{}\nallocated bytes: {}\nfreed bytes: {}\nallocations: {}\ndeallocations: {}\n", | |
| 1090 | // fail_index, needed_alloc_count, | |
| 1091 | // failing_allocator.allocated_bytes, failing_allocator.freed_bytes, | |
| 1092 | // failing_allocator.index, failing_allocator.deallocations); | |
| 1093 | // return error.MemoryLeakDetected; | |
| 1094 | //} | |
| 1084 | } else |err| switch (err) { | |
| 1085 | error.OutOfMemory => { | |
| 1086 | // TODO make this pass | |
| 1087 | //if (failing_allocator.allocated_bytes != failing_allocator.freed_bytes) { | |
| 1088 | // warn("\nfail_index: {}/{}\nallocated bytes: {}\nfreed bytes: {}\nallocations: {}\ndeallocations: {}\n", | |
| 1089 | // fail_index, needed_alloc_count, | |
| 1090 | // failing_allocator.allocated_bytes, failing_allocator.freed_bytes, | |
| 1091 | // failing_allocator.index, failing_allocator.deallocations); | |
| 1092 | // return error.MemoryLeakDetected; | |
| 1093 | //} | |
| 1094 | }, | |
| 1095 | error.ParseError => @panic("test failed"), | |
| 1095 | 1096 | } |
| 1096 | 1097 | } |
| 1097 | 1098 | } |
test/compile_errors.zig+12| ... | ... | @@ -1,6 +1,18 @@ |
| 1 | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | |
| 3 | 3 | pub fn addCases(cases: &tests.CompileErrorContext) void { |
| 4 | cases.add("no else prong on switch on global error set", | |
| 5 | \\export fn entry() void { | |
| 6 | \\ foo(error.A); | |
| 7 | \\} | |
| 8 | \\fn foo(a: error) void { | |
| 9 | \\ switch (a) { | |
| 10 | \\ error.A => {}, | |
| 11 | \\ } | |
| 12 | \\} | |
| 13 | , | |
| 14 | ".tmp_source.zig:5:5: error: else prong required when switching on type 'error'"); | |
| 15 | ||
| 4 | 16 | cases.add("inferred error set with no returned error", |
| 5 | 17 | \\export fn entry() void { |
| 6 | 18 | \\ foo() catch unreachable; |