authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-08 02:08:45-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-08 02:08:45-05:00
log0d5ff6f4622a492dddbb1fc2b19b3157237500b1
tree4a707f626dc12adeeed3438b5966876c6b401ea0
parent68238d5678a4c055bb6f1206254dcac2e0c634f0

error sets - most tests passing


28 files changed, 333 insertions(+), 121 deletions(-)

TODO+11
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1sed -i 's/\(\bfn .*) \)%\(.*{\)$/\1!\2/g' $(find . -name "*.zig")1sed -i 's/\(\bfn .*) \)%\(.*{\)$/\1!\2/g' $(find . -name "*.zig")
22
3
3the literal translation of `%T` to this new code is `error!T`.4the literal translation of `%T` to this new code is `error!T`.
4however this would not take advantage of error sets. It's5however this would not take advantage of error sets. It's
5recommended to generally have all your functions which return possible6recommended to generally have all your functions which return possible
...@@ -11,6 +12,11 @@ fn foo() !void {...@@ -11,6 +12,11 @@ fn foo() !void {
1112
12then you can return void, or any error, and the error set is inferred.13then you can return void, or any error, and the error set is inferred.
1314
15
16you can get the compiler to tell you the possible errors for an inferred error set like this:
17
18foo() catch |err| switch (err) {};
19
14// TODO this is an explicit cast and should actually coerce the type20// TODO this is an explicit cast and should actually coerce the type
15 erorr set casting21 erorr set casting
1622
...@@ -27,3 +33,8 @@ comptime test for err...@@ -27,3 +33,8 @@ comptime test for err
27undefined in infer error 33undefined in infer error
2834
29syntax - ?a!b should be ?(a!b) but it's (?a)!b35syntax - ?a!b should be ?(a!b) but it's (?a)!b
36
37syntax - (error{}!void) as the return type
38
39
40passing a fn()error{}!T to a fn()error!T should be a compile error, they're not compatible
doc/docgen.zig+2-11
...@@ -42,7 +42,7 @@ pub fn main() !void {...@@ -42,7 +42,7 @@ pub fn main() !void {
42 const input_file_bytes = try file_in_stream.stream.readAllAlloc(allocator, max_doc_file_size);42 const input_file_bytes = try file_in_stream.stream.readAllAlloc(allocator, max_doc_file_size);
4343
44 var file_out_stream = io.FileOutStream.init(&out_file);44 var file_out_stream = io.FileOutStream.init(&out_file);
45 var buffered_out_stream = io.BufferedOutStream.init(&file_out_stream.stream);45 var buffered_out_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream);
4646
47 var tokenizer = Tokenizer.init(in_file_name, input_file_bytes);47 var tokenizer = Tokenizer.init(in_file_name, input_file_bytes);
48 var toc = try genToc(allocator, &tokenizer);48 var toc = try genToc(allocator, &tokenizer);
...@@ -218,8 +218,6 @@ const Tokenizer = struct {...@@ -218,8 +218,6 @@ const Tokenizer = struct {
218 }218 }
219};219};
220220
221error ParseError;
222
223fn parseError(tokenizer: &Tokenizer, token: &const Token, comptime fmt: []const u8, args: ...) error {221fn parseError(tokenizer: &Tokenizer, token: &const Token, comptime fmt: []const u8, args: ...) error {
224 const loc = tokenizer.getTokenLocation(token);222 const loc = tokenizer.getTokenLocation(token);
225 warn("{}:{}:{}: error: " ++ fmt ++ "\n", tokenizer.source_file_name, loc.line + 1, loc.column + 1, args);223 warn("{}:{}:{}: error: " ++ fmt ++ "\n", tokenizer.source_file_name, loc.line + 1, loc.column + 1, args);
...@@ -596,8 +594,6 @@ const TermState = enum {...@@ -596,8 +594,6 @@ const TermState = enum {
596 ExpectEnd,594 ExpectEnd,
597};595};
598596
599error UnsupportedEscape;
600
601test "term color" {597test "term color" {
602 const input_bytes = "A\x1b[32;1mgreen\x1b[0mB";598 const input_bytes = "A\x1b[32;1mgreen\x1b[0mB";
603 const result = try termColor(std.debug.global_allocator, input_bytes);599 const result = try termColor(std.debug.global_allocator, input_bytes);
...@@ -684,9 +680,7 @@ fn termColor(allocator: &mem.Allocator, input: []const u8) ![]u8 {...@@ -684,9 +680,7 @@ fn termColor(allocator: &mem.Allocator, input: []const u8) ![]u8 {
684 return buf.toOwnedSlice();680 return buf.toOwnedSlice();
685}681}
686682
687error ExampleFailedToCompile;683fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var, zig_exe: []const u8) !void {
688
689fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io.OutStream, zig_exe: []const u8) !void {
690 var code_progress_index: usize = 0;684 var code_progress_index: usize = 0;
691 for (toc.nodes) |node| {685 for (toc.nodes) |node| {
692 switch (node) {686 switch (node) {
...@@ -974,9 +968,6 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io...@@ -974,9 +968,6 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io
974968
975}969}
976970
977error ChildCrashed;
978error ChildExitError;
979
980fn exec(allocator: &mem.Allocator, args: []const []const u8) !os.ChildProcess.ExecResult {971fn exec(allocator: &mem.Allocator, args: []const []const u8) !os.ChildProcess.ExecResult {
981 const result = try os.ChildProcess.exec(allocator, args, null, null, max_doc_file_size);972 const result = try os.ChildProcess.exec(allocator, args, null, null, max_doc_file_size);
982 switch (result.term) {973 switch (result.term) {
example/cat/main.zig+1-1
...@@ -61,7 +61,7 @@ fn cat_file(stdout: &io.File, file: &io.File) !void {...@@ -61,7 +61,7 @@ fn cat_file(stdout: &io.File, file: &io.File) !void {
61 }61 }
62}62}
6363
64fn unwrapArg(arg: %[]u8) ![]u8 {64fn unwrapArg(arg: error![]u8) ![]u8 {
65 return arg catch |err| {65 return arg catch |err| {
66 warn("Unable to parse command line: {}\n", err);66 warn("Unable to parse command line: {}\n", err);
67 return err;67 return err;
example/mix_o_files/build.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) !void {3pub fn build(b: &Builder) void {
4 const obj = b.addObject("base64", "base64.zig");4 const obj = b.addObject("base64", "base64.zig");
55
6 const exe = b.addCExecutable("test");6 const exe = b.addCExecutable("test");
example/shared_library/build.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) !void {3pub fn build(b: &Builder) void {
4 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));4 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
55
6 const exe = b.addCExecutable("test");6 const exe = b.addCExecutable("test");
src-self-hosted/main.zig+1-5
...@@ -14,10 +14,6 @@ const builtin = @import("builtin");...@@ -14,10 +14,6 @@ const builtin = @import("builtin");
14const ArrayList = std.ArrayList;14const ArrayList = std.ArrayList;
15const c = @import("c.zig");15const c = @import("c.zig");
1616
17error InvalidCommandLineArguments;
18error ZigLibDirNotFound;
19error ZigInstallationNotFound;
20
21const default_zig_cache_name = "zig-cache";17const default_zig_cache_name = "zig-cache";
2218
23pub fn main() !void {19pub fn main() !void {
...@@ -472,7 +468,7 @@ pub fn main2() !void {...@@ -472,7 +468,7 @@ pub fn main2() !void {
472 }468 }
473}469}
474470
475fn printUsage(stream: &io.OutStream) !void {471fn printUsage(stream: var) !void {
476 try stream.write(472 try stream.write(
477 \\Usage: zig [command] [options]473 \\Usage: zig [command] [options]
478 \\474 \\
src-self-hosted/module.zig+2-1
...@@ -110,7 +110,7 @@ pub const Module = struct {...@@ -110,7 +110,7 @@ pub const Module = struct {
110 };110 };
111111
112 pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target,112 pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target,
113 kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) %&Module113 kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !&Module
114 {114 {
115 var name_buffer = try Buffer.init(allocator, name);115 var name_buffer = try Buffer.init(allocator, name);
116 errdefer name_buffer.deinit();116 errdefer name_buffer.deinit();
...@@ -265,6 +265,7 @@ pub const Module = struct {...@@ -265,6 +265,7 @@ pub const Module = struct {
265265
266 pub fn link(self: &Module, out_file: ?[]const u8) !void {266 pub fn link(self: &Module, out_file: ?[]const u8) !void {
267 warn("TODO link");267 warn("TODO link");
268 return error.Todo;
268 }269 }
269270
270 pub fn addLinkLib(self: &Module, name: []const u8, provided_explicitly: bool) !&LinkLib {271 pub fn addLinkLib(self: &Module, name: []const u8, provided_explicitly: bool) !&LinkLib {
src-self-hosted/parser.zig+6-12
...@@ -12,8 +12,6 @@ const io = std.io;...@@ -12,8 +12,6 @@ const io = std.io;
12// get rid of this12// get rid of this
13const warn = std.debug.warn;13const warn = std.debug.warn;
1414
15error ParseError;
16
17pub const Parser = struct {15pub const Parser = struct {
18 allocator: &mem.Allocator,16 allocator: &mem.Allocator,
19 tokenizer: &Tokenizer,17 tokenizer: &Tokenizer,
...@@ -555,7 +553,7 @@ pub const Parser = struct {...@@ -555,7 +553,7 @@ pub const Parser = struct {
555 }553 }
556554
557 fn createVarDecl(self: &Parser, visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token,555 fn createVarDecl(self: &Parser, visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token,
558 extern_token: &const ?Token) %&ast.NodeVarDecl556 extern_token: &const ?Token) !&ast.NodeVarDecl
559 {557 {
560 const node = try self.allocator.create(ast.NodeVarDecl);558 const node = try self.allocator.create(ast.NodeVarDecl);
561559
...@@ -577,7 +575,7 @@ pub const Parser = struct {...@@ -577,7 +575,7 @@ pub const Parser = struct {
577 }575 }
578576
579 fn createFnProto(self: &Parser, fn_token: &const Token, extern_token: &const ?Token,577 fn createFnProto(self: &Parser, fn_token: &const Token, extern_token: &const ?Token,
580 cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) %&ast.NodeFnProto578 cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) !&ast.NodeFnProto
581 {579 {
582 const node = try self.allocator.create(ast.NodeFnProto);580 const node = try self.allocator.create(ast.NodeFnProto);
583581
...@@ -694,7 +692,7 @@ pub const Parser = struct {...@@ -694,7 +692,7 @@ pub const Parser = struct {
694692
695 fn createAttachFnProto(self: &Parser, list: &ArrayList(&ast.Node), fn_token: &const Token,693 fn createAttachFnProto(self: &Parser, list: &ArrayList(&ast.Node), fn_token: &const Token,
696 extern_token: &const ?Token, cc_token: &const ?Token, visib_token: &const ?Token,694 extern_token: &const ?Token, cc_token: &const ?Token, visib_token: &const ?Token,
697 inline_token: &const ?Token) %&ast.NodeFnProto695 inline_token: &const ?Token) !&ast.NodeFnProto
698 {696 {
699 const node = try self.createFnProto(fn_token, extern_token, cc_token, visib_token, inline_token);697 const node = try self.createFnProto(fn_token, extern_token, cc_token, visib_token, inline_token);
700 try list.append(&node.base);698 try list.append(&node.base);
...@@ -702,7 +700,7 @@ pub const Parser = struct {...@@ -702,7 +700,7 @@ pub const Parser = struct {
702 }700 }
703701
704 fn createAttachVarDecl(self: &Parser, list: &ArrayList(&ast.Node), visib_token: &const ?Token,702 fn createAttachVarDecl(self: &Parser, list: &ArrayList(&ast.Node), visib_token: &const ?Token,
705 mut_token: &const Token, comptime_token: &const ?Token, extern_token: &const ?Token) %&ast.NodeVarDecl703 mut_token: &const Token, comptime_token: &const ?Token, extern_token: &const ?Token) !&ast.NodeVarDecl
706 {704 {
707 const node = try self.createVarDecl(visib_token, mut_token, comptime_token, extern_token);705 const node = try self.createVarDecl(visib_token, mut_token, comptime_token, extern_token);
708 try list.append(&node.base);706 try list.append(&node.base);
...@@ -763,7 +761,7 @@ pub const Parser = struct {...@@ -763,7 +761,7 @@ pub const Parser = struct {
763 indent: usize,761 indent: usize,
764 };762 };
765763
766 pub fn renderAst(self: &Parser, stream: &std.io.OutStream, root_node: &ast.NodeRoot) !void {764 pub fn renderAst(self: &Parser, stream: var, root_node: &ast.NodeRoot) !void {
767 var stack = self.initUtilityArrayList(RenderAstFrame);765 var stack = self.initUtilityArrayList(RenderAstFrame);
768 defer self.deinitUtilityArrayList(stack);766 defer self.deinitUtilityArrayList(stack);
769767
...@@ -802,7 +800,7 @@ pub const Parser = struct {...@@ -802,7 +800,7 @@ pub const Parser = struct {
802 Indent: usize,800 Indent: usize,
803 };801 };
804802
805 pub fn renderSource(self: &Parser, stream: &std.io.OutStream, root_node: &ast.NodeRoot) !void {803 pub fn renderSource(self: &Parser, stream: var, root_node: &ast.NodeRoot) !void {
806 var stack = self.initUtilityArrayList(RenderState);804 var stack = self.initUtilityArrayList(RenderState);
807 defer self.deinitUtilityArrayList(stack);805 defer self.deinitUtilityArrayList(stack);
808806
...@@ -1058,10 +1056,6 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {...@@ -1058,10 +1056,6 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {
1058 return buffer.toOwnedSlice();1056 return buffer.toOwnedSlice();
1059}1057}
10601058
1061error TestFailed;
1062error NondeterministicMemoryUsage;
1063error MemoryLeakDetected;
1064
1065// TODO test for memory leaks1059// TODO test for memory leaks
1066// TODO test for valid frees1060// TODO test for valid frees
1067fn testCanonical(source: []const u8) !void {1061fn testCanonical(source: []const u8) !void {
src/ir.cpp+72-4
...@@ -5442,6 +5442,10 @@ static TypeTableEntry *get_error_set_union(CodeGen *g, ErrorTableEntry **errors,...@@ -5442,6 +5442,10 @@ static TypeTableEntry *get_error_set_union(CodeGen *g, ErrorTableEntry **errors,
5442 buf_resize(&err_set_type->name, 0);5442 buf_resize(&err_set_type->name, 0);
5443 buf_appendf(&err_set_type->name, "error{");5443 buf_appendf(&err_set_type->name, "error{");
54445444
5445 for (uint32_t i = 0, count = set1->data.error_set.err_count; i < count; i += 1) {
5446 assert(errors[set1->data.error_set.errors[i]->value] == set1->data.error_set.errors[i]);
5447 }
5448
5445 uint32_t count = set1->data.error_set.err_count;5449 uint32_t count = set1->data.error_set.err_count;
5446 for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) {5450 for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) {
5447 ErrorTableEntry *error_entry = set2->data.error_set.errors[i];5451 ErrorTableEntry *error_entry = set2->data.error_set.errors[i];
...@@ -5523,6 +5527,8 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A...@@ -5523,6 +5527,8 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A
5523 err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count);5527 err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count);
5524 }5528 }
55255529
5530 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(irb->codegen->errors_by_index.length + err_count);
5531
5526 for (uint32_t i = 0; i < err_count; i += 1) {5532 for (uint32_t i = 0; i < err_count; i += 1) {
5527 AstNode *symbol_node = node->data.err_set_decl.decls.at(i);5533 AstNode *symbol_node = node->data.err_set_decl.decls.at(i);
5528 assert(symbol_node->type == NodeTypeSymbol);5534 assert(symbol_node->type == NodeTypeSymbol);
...@@ -5543,7 +5549,16 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A...@@ -5543,7 +5549,16 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A
5543 buf_ptr(err_name), error_value_count));5549 buf_ptr(err_name), error_value_count));
5544 }5550 }
5545 err_set_type->data.error_set.errors[i] = err;5551 err_set_type->data.error_set.errors[i] = err;
5552
5553 ErrorTableEntry *prev_err = errors[err->value];
5554 if (prev_err != nullptr) {
5555 ErrorMsg *msg = add_node_error(irb->codegen, err->decl_node, buf_sprintf("duplicate error: '%s'", buf_ptr(&err->name)));
5556 add_error_note(irb->codegen, msg, prev_err->decl_node, buf_sprintf("other error here"));
5557 return irb->codegen->invalid_instruction;
5558 }
5559 errors[err->value] = err;
5546 }5560 }
5561 free(errors);
5547 return ir_build_const_type(irb, parent_scope, node, err_set_type);5562 return ir_build_const_type(irb, parent_scope, node, err_set_type);
5548}5563}
55495564
...@@ -6512,6 +6527,7 @@ static TypeTableEntry *get_error_set_intersection(IrAnalyze *ira, TypeTableEntry...@@ -6512,6 +6527,7 @@ static TypeTableEntry *get_error_set_intersection(IrAnalyze *ira, TypeTableEntry
6512 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);6527 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
6513 for (uint32_t i = 0; i < set1->data.error_set.err_count; i += 1) {6528 for (uint32_t i = 0; i < set1->data.error_set.err_count; i += 1) {
6514 ErrorTableEntry *error_entry = set1->data.error_set.errors[i];6529 ErrorTableEntry *error_entry = set1->data.error_set.errors[i];
6530 assert(errors[error_entry->value] == nullptr);
6515 errors[error_entry->value] = error_entry;6531 errors[error_entry->value] = error_entry;
6516 }6532 }
6517 ZigList<ErrorTableEntry *> intersection_list = {};6533 ZigList<ErrorTableEntry *> intersection_list = {};
...@@ -6653,6 +6669,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry...@@ -6653,6 +6669,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
6653 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(g->errors_by_index.length);6669 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(g->errors_by_index.length);
6654 for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) {6670 for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) {
6655 ErrorTableEntry *error_entry = container_set->data.error_set.errors[i];6671 ErrorTableEntry *error_entry = container_set->data.error_set.errors[i];
6672 assert(errors[error_entry->value] == nullptr);
6656 errors[error_entry->value] = error_entry;6673 errors[error_entry->value] = error_entry;
6657 }6674 }
6658 for (uint32_t i = 0; i < contained_set->data.error_set.err_count; i += 1) {6675 for (uint32_t i = 0; i < contained_set->data.error_set.err_count; i += 1) {
...@@ -6767,6 +6784,12 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,...@@ -6767,6 +6784,12 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
6767 buf_sprintf("unable to cast global error set into smaller set"));6784 buf_sprintf("unable to cast global error set into smaller set"));
6768 return ImplicitCastMatchResultReportedError;6785 return ImplicitCastMatchResultReportedError;
6769 }6786 }
6787 } else if (const_cast_result.id == ConstCastResultIdErrSetGlobal) {
6788 ErrorMsg *msg = ir_add_error(ira, value,
6789 buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));
6790 add_error_note(ira->codegen, msg, value->source_node,
6791 buf_sprintf("unable to cast global error set into smaller set"));
6792 return ImplicitCastMatchResultReportedError;
6770 }6793 }
6771 if (missing_errors != nullptr) {6794 if (missing_errors != nullptr) {
6772 ErrorMsg *msg = ir_add_error(ira, value,6795 ErrorMsg *msg = ir_add_error(ira, value,
...@@ -6995,6 +7018,12 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,...@@ -6995,6 +7018,12 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
6995 return ImplicitCastMatchResultNo;7018 return ImplicitCastMatchResultNo;
6996}7019}
69977020
7021static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t *errors_count) {
7022 size_t old_errors_count = *errors_count;
7023 *errors_count = g->errors_by_index.length;
7024 *errors = reallocate(*errors, old_errors_count, *errors_count);
7025}
7026
6998static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) {7027static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) {
6999 assert(instruction_count >= 1);7028 assert(instruction_count >= 1);
7000 IrInstruction *prev_inst = instructions[0];7029 IrInstruction *prev_inst = instructions[0];
...@@ -7002,6 +7031,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -7002,6 +7031,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
7002 return ira->codegen->builtin_types.entry_invalid;7031 return ira->codegen->builtin_types.entry_invalid;
7003 }7032 }
7004 ErrorTableEntry **errors = nullptr;7033 ErrorTableEntry **errors = nullptr;
7034 size_t errors_count = 0;
7005 TypeTableEntry *err_set_type = nullptr;7035 TypeTableEntry *err_set_type = nullptr;
7006 if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) {7036 if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) {
7007 if (type_is_global_error_set(prev_inst->value.type)) {7037 if (type_is_global_error_set(prev_inst->value.type)) {
...@@ -7011,9 +7041,11 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -7011,9 +7041,11 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
7011 if (!resolve_inferred_error_set(ira, err_set_type, prev_inst->source_node)) {7041 if (!resolve_inferred_error_set(ira, err_set_type, prev_inst->source_node)) {
7012 return ira->codegen->builtin_types.entry_invalid;7042 return ira->codegen->builtin_types.entry_invalid;
7013 }7043 }
7014 errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);7044 update_errors_helper(ira->codegen, &errors, &errors_count);
7045
7015 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {7046 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
7016 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];7047 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
7048 assert(errors[error_entry->value] == nullptr);
7017 errors[error_entry->value] = error_entry;7049 errors[error_entry->value] = error_entry;
7018 }7050 }
7019 }7051 }
...@@ -7064,6 +7096,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -7064,6 +7096,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
7064 continue;7096 continue;
7065 }7097 }
70667098
7099 // number of declared errors might have increased now
7100 update_errors_helper(ira->codegen, &errors, &errors_count);
7101
7067 // if err_set_type is a superset of cur_type, keep err_set_type.7102 // if err_set_type is a superset of cur_type, keep err_set_type.
7068 // if cur_type is a superset of err_set_type, switch err_set_type to cur_type7103 // if cur_type is a superset of err_set_type, switch err_set_type to cur_type
7069 bool prev_is_superset = true;7104 bool prev_is_superset = true;
...@@ -7084,8 +7119,12 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -7084,8 +7119,12 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
7084 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];7119 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
7085 errors[error_entry->value] = nullptr;7120 errors[error_entry->value] = nullptr;
7086 }7121 }
7122 for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) {
7123 assert(errors[i] == nullptr);
7124 }
7087 for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) {7125 for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) {
7088 ErrorTableEntry *error_entry = cur_type->data.error_set.errors[i];7126 ErrorTableEntry *error_entry = cur_type->data.error_set.errors[i];
7127 assert(errors[error_entry->value] == nullptr);
7089 errors[error_entry->value] = error_entry;7128 errors[error_entry->value] = error_entry;
7090 }7129 }
7091 bool cur_is_superset = true;7130 bool cur_is_superset = true;
...@@ -7122,14 +7161,21 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -7122,14 +7161,21 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
7122 prev_inst = cur_inst;7161 prev_inst = cur_inst;
7123 continue;7162 continue;
7124 }7163 }
7164
7165 update_errors_helper(ira->codegen, &errors, &errors_count);
7166
7125 // test if err_set_type is a subset of cur_type's error set7167 // test if err_set_type is a subset of cur_type's error set
7126 // unset everything in errors7168 // unset everything in errors
7127 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {7169 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
7128 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];7170 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
7129 errors[error_entry->value] = nullptr;7171 errors[error_entry->value] = nullptr;
7130 }7172 }
7173 for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) {
7174 assert(errors[i] == nullptr);
7175 }
7131 for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) {7176 for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) {
7132 ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i];7177 ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i];
7178 assert(errors[error_entry->value] == nullptr);
7133 errors[error_entry->value] = error_entry;7179 errors[error_entry->value] = error_entry;
7134 }7180 }
7135 bool cur_is_superset = true;7181 bool cur_is_superset = true;
...@@ -7173,15 +7219,18 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -7173,15 +7219,18 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
7173 if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) {7219 if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) {
7174 return ira->codegen->builtin_types.entry_invalid;7220 return ira->codegen->builtin_types.entry_invalid;
7175 }7221 }
7222
7223 update_errors_helper(ira->codegen, &errors, &errors_count);
7224
7176 if (err_set_type == nullptr) {7225 if (err_set_type == nullptr) {
7177 if (prev_type->id == TypeTableEntryIdErrorUnion) {7226 if (prev_type->id == TypeTableEntryIdErrorUnion) {
7178 err_set_type = prev_type->data.error_union.err_set_type;7227 err_set_type = prev_type->data.error_union.err_set_type;
7179 } else {7228 } else {
7180 err_set_type = cur_type;7229 err_set_type = cur_type;
7181 }7230 }
7182 errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
7183 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {7231 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
7184 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];7232 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
7233 assert(errors[error_entry->value] == nullptr);
7185 errors[error_entry->value] = error_entry;7234 errors[error_entry->value] = error_entry;
7186 }7235 }
7187 if (err_set_type == cur_type) {7236 if (err_set_type == cur_type) {
...@@ -7237,11 +7286,13 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -7237,11 +7286,13 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
7237 continue;7286 continue;
7238 }7287 }
72397288
7289 update_errors_helper(ira->codegen, &errors, &errors_count);
7290
7240 if (err_set_type == nullptr) {7291 if (err_set_type == nullptr) {
7241 err_set_type = prev_err_set_type;7292 err_set_type = prev_err_set_type;
7242 errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
7243 for (uint32_t i = 0; i < prev_err_set_type->data.error_set.err_count; i += 1) {7293 for (uint32_t i = 0; i < prev_err_set_type->data.error_set.err_count; i += 1) {
7244 ErrorTableEntry *error_entry = prev_err_set_type->data.error_set.errors[i];7294 ErrorTableEntry *error_entry = prev_err_set_type->data.error_set.errors[i];
7295 assert(errors[error_entry->value] == nullptr);
7245 errors[error_entry->value] = error_entry;7296 errors[error_entry->value] = error_entry;
7246 }7297 }
7247 }7298 }
...@@ -7262,8 +7313,12 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -7262,8 +7313,12 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
7262 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];7313 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
7263 errors[error_entry->value] = nullptr;7314 errors[error_entry->value] = nullptr;
7264 }7315 }
7316 for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) {
7317 assert(errors[i] == nullptr);
7318 }
7265 for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) {7319 for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) {
7266 ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i];7320 ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i];
7321 assert(errors[error_entry->value] == nullptr);
7267 errors[error_entry->value] = error_entry;7322 errors[error_entry->value] = error_entry;
7268 }7323 }
7269 bool cur_is_superset = true;7324 bool cur_is_superset = true;
...@@ -7331,6 +7386,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -7331,6 +7386,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
7331 continue;7386 continue;
7332 }7387 }
73337388
7389 update_errors_helper(ira->codegen, &errors, &errors_count);
7390
7334 err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_err_set_type);7391 err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_err_set_type);
7335 }7392 }
7336 prev_inst = cur_inst;7393 prev_inst = cur_inst;
...@@ -8000,6 +8057,7 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou...@@ -8000,6 +8057,7 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou
8000 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);8057 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
8001 for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) {8058 for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) {
8002 ErrorTableEntry *error_entry = container_set->data.error_set.errors[i];8059 ErrorTableEntry *error_entry = container_set->data.error_set.errors[i];
8060 assert(errors[error_entry->value] == nullptr);
8003 errors[error_entry->value] = error_entry;8061 errors[error_entry->value] = error_entry;
8004 }8062 }
8005 ErrorMsg *err_msg = nullptr;8063 ErrorMsg *err_msg = nullptr;
...@@ -10212,8 +10270,9 @@ static TypeTableEntry *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstruction...@@ -10212,8 +10270,9 @@ static TypeTableEntry *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstruction
10212 }10270 }
1021310271
10214 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);10272 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
10215 for (uint32_t i = 0; i < op1_type->data.error_set.err_count; i += 1) {10273 for (uint32_t i = 0, count = op1_type->data.error_set.err_count; i < count; i += 1) {
10216 ErrorTableEntry *error_entry = op1_type->data.error_set.errors[i];10274 ErrorTableEntry *error_entry = op1_type->data.error_set.errors[i];
10275 assert(errors[error_entry->value] == nullptr);
10217 errors[error_entry->value] = error_entry;10276 errors[error_entry->value] = error_entry;
10218 }10277 }
10219 TypeTableEntry *result_type = get_error_set_union(ira->codegen, errors, op1_type, op2_type);10278 TypeTableEntry *result_type = get_error_set_union(ira->codegen, errors, op1_type, op2_type);
...@@ -14987,6 +15046,15 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns...@@ -14987,6 +15046,15 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns
14987 result = container_type->data.structure.src_field_count;15046 result = container_type->data.structure.src_field_count;
14988 } else if (container_type->id == TypeTableEntryIdUnion) {15047 } else if (container_type->id == TypeTableEntryIdUnion) {
14989 result = container_type->data.unionation.src_field_count;15048 result = container_type->data.unionation.src_field_count;
15049 } else if (container_type->id == TypeTableEntryIdErrorSet) {
15050 if (!resolve_inferred_error_set(ira, container_type, instruction->base.source_node)) {
15051 return ira->codegen->builtin_types.entry_invalid;
15052 }
15053 if (type_is_global_error_set(container_type)) {
15054 ir_add_error(ira, &instruction->base, buf_sprintf("global error set member count not available at comptime"));
15055 return ira->codegen->builtin_types.entry_invalid;
15056 }
15057 result = container_type->data.error_set.err_count;
14990 } else {15058 } else {
14991 ir_add_error(ira, &instruction->base, buf_sprintf("no value count available for type '%s'", buf_ptr(&container_type->name)));15059 ir_add_error(ira, &instruction->base, buf_sprintf("no value count available for type '%s'", buf_ptr(&container_type->name)));
14992 return ira->codegen->builtin_types.entry_invalid;15060 return ira->codegen->builtin_types.entry_invalid;
src/util.hpp+11-8
...@@ -92,19 +92,22 @@ static inline void safe_memcpy(T *dest, const T *src, size_t count) {...@@ -92,19 +92,22 @@ static inline void safe_memcpy(T *dest, const T *src, size_t count) {
92}92}
9393
94template<typename T>94template<typename T>
95static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) {95static inline T *reallocate(T *old, size_t old_count, size_t new_count) {
96#ifdef NDEBUG
97 T *ptr = reinterpret_cast<T*>(realloc(old, new_count * sizeof(T)));96 T *ptr = reinterpret_cast<T*>(realloc(old, new_count * sizeof(T)));
98 if (!ptr)97 if (!ptr)
99 zig_panic("allocation failed");98 zig_panic("allocation failed");
99 if (new_count > old_count) {
100 memset(&ptr[old_count], 0, (new_count - old_count) * sizeof(T));
101 }
100 return ptr;102 return ptr;
101#else103}
102 // manually assign every element to trigger compile error for non-copyable structs104
103 T *ptr = allocate_nonzero<T>(new_count);105template<typename T>
104 safe_memcpy(ptr, old, old_count);106static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) {
105 free(old);107 T *ptr = reinterpret_cast<T*>(realloc(old, new_count * sizeof(T)));
108 if (!ptr)
109 zig_panic("allocation failed");
106 return ptr;110 return ptr;
107#endif
108}111}
109112
110template <typename T, size_t n>113template <typename T, size_t n>
std/build.zig+4-4
...@@ -271,7 +271,7 @@ pub const Builder = struct {...@@ -271,7 +271,7 @@ pub const Builder = struct {
271 return &self.uninstall_tls.step;271 return &self.uninstall_tls.step;
272 }272 }
273273
274 fn makeUninstall(uninstall_step: &Step) !void {274 fn makeUninstall(uninstall_step: &Step) error!void {
275 const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step);275 const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step);
276 const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls);276 const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls);
277277
...@@ -285,7 +285,7 @@ pub const Builder = struct {...@@ -285,7 +285,7 @@ pub const Builder = struct {
285 // TODO remove empty directories285 // TODO remove empty directories
286 }286 }
287287
288 fn makeOneStep(self: &Builder, s: &Step) !void {288 fn makeOneStep(self: &Builder, s: &Step) error!void {
289 if (s.loop_flag) {289 if (s.loop_flag) {
290 warn("Dependency loop detected:\n {}\n", s.name);290 warn("Dependency loop detected:\n {}\n", s.name);
291 return error.DependencyLoopDetected;291 return error.DependencyLoopDetected;
...@@ -1910,7 +1910,7 @@ pub const LogStep = struct {...@@ -1910,7 +1910,7 @@ pub const LogStep = struct {
1910 };1910 };
1911 }1911 }
19121912
1913 fn make(step: &Step) !void {1913 fn make(step: &Step) error!void {
1914 const self = @fieldParentPtr(LogStep, "step", step);1914 const self = @fieldParentPtr(LogStep, "step", step);
1915 warn("{}", self.data);1915 warn("{}", self.data);
1916 }1916 }
...@@ -1972,7 +1972,7 @@ pub const Step = struct {...@@ -1972,7 +1972,7 @@ pub const Step = struct {
1972 self.dependencies.append(other) catch unreachable;1972 self.dependencies.append(other) catch unreachable;
1973 }1973 }
19741974
1975 fn makeNoOp(self: &Step) (error{}!void) {}1975 fn makeNoOp(self: &Step) error!void {}
1976};1976};
19771977
1978fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_major_only: []const u8,1978fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_major_only: []const u8,
std/fmt/index.zig+1-1
...@@ -510,7 +510,7 @@ pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ......@@ -510,7 +510,7 @@ pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...
510 return bufPrint(buf, fmt, args);510 return bufPrint(buf, fmt, args);
511}511}
512512
513fn countSize(size: &usize, bytes: []const u8) !void {513fn countSize(size: &usize, bytes: []const u8) (error{}!void) {
514 *size += bytes.len;514 *size += bytes.len;
515}515}
516516
std/io.zig+2-2
...@@ -694,13 +694,13 @@ pub const BufferOutStream = struct {...@@ -694,13 +694,13 @@ pub const BufferOutStream = struct {
694 pub fn init(buffer: &Buffer) BufferOutStream {694 pub fn init(buffer: &Buffer) BufferOutStream {
695 return BufferOutStream {695 return BufferOutStream {
696 .buffer = buffer,696 .buffer = buffer,
697 .stream = OutStream {697 .stream = Stream {
698 .writeFn = writeFn,698 .writeFn = writeFn,
699 },699 },
700 };700 };
701 }701 }
702702
703 fn writeFn(out_stream: &OutStream, bytes: []const u8) !void {703 fn writeFn(out_stream: &Stream, bytes: []const u8) !void {
704 const self = @fieldParentPtr(BufferOutStream, "stream", out_stream);704 const self = @fieldParentPtr(BufferOutStream, "stream", out_stream);
705 return self.buffer.append(bytes);705 return self.buffer.append(bytes);
706 }706 }
std/os/child_process.zig+18-3
...@@ -55,7 +55,22 @@ pub const ChildProcess = struct {...@@ -55,7 +55,22 @@ pub const ChildProcess = struct {
55 llnode: if (is_windows) void else LinkedList(&ChildProcess).Node,55 llnode: if (is_windows) void else LinkedList(&ChildProcess).Node,
5656
57 pub const SpawnError = error {57 pub const SpawnError = error {
5858 ProcessFdQuotaExceeded,
59 Unexpected,
60 NotDir,
61 SystemResources,
62 FileNotFound,
63 NameTooLong,
64 SymLinkLoop,
65 FileSystem,
66 OutOfMemory,
67 AccessDenied,
68 PermissionDenied,
69 InvalidUserId,
70 ResourceLimitReached,
71 InvalidExe,
72 IsDir,
73 FileBusy,
59 };74 };
6075
61 pub const Term = union(enum) {76 pub const Term = union(enum) {
...@@ -313,7 +328,7 @@ pub const ChildProcess = struct {...@@ -313,7 +328,7 @@ pub const ChildProcess = struct {
313 // Here we potentially return the fork child's error328 // Here we potentially return the fork child's error
314 // from the parent pid.329 // from the parent pid.
315 if (err_int != @maxValue(ErrInt)) {330 if (err_int != @maxValue(ErrInt)) {
316 return error(err_int);331 return SpawnError(err_int);
317 }332 }
318333
319 return statusToTerm(status);334 return statusToTerm(status);
...@@ -757,7 +772,7 @@ fn destroyPipe(pipe: &const [2]i32) void {...@@ -757,7 +772,7 @@ fn destroyPipe(pipe: &const [2]i32) void {
757772
758// Child of fork calls this to report an error to the fork parent.773// Child of fork calls this to report an error to the fork parent.
759// Then the child exits.774// Then the child exits.
760fn forkChildErrReport(fd: i32, err: error) noreturn {775fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
761 _ = writeIntFd(fd, ErrInt(err));776 _ = writeIntFd(fd, ErrInt(err));
762 posix.exit(1);777 posix.exit(1);
763}778}
std/os/index.zig+80-19
...@@ -243,7 +243,6 @@ pub const PosixOpenError = error {...@@ -243,7 +243,6 @@ pub const PosixOpenError = error {
243 SystemResources,243 SystemResources,
244 NoSpaceLeft,244 NoSpaceLeft,
245 NotDir,245 NotDir,
246 AccessDenied,
247 PathAlreadyExists,246 PathAlreadyExists,
248 Unexpected,247 Unexpected,
249};248};
...@@ -411,7 +410,19 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,...@@ -411,7 +410,19 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,
411 return posixExecveErrnoToErr(err);410 return posixExecveErrnoToErr(err);
412}411}
413412
414fn posixExecveErrnoToErr(err: usize) error {413pub const PosixExecveError = error {
414 SystemResources,
415 AccessDenied,
416 InvalidExe,
417 FileSystem,
418 IsDir,
419 FileNotFound,
420 NotDir,
421 FileBusy,
422 Unexpected,
423};
424
425fn posixExecveErrnoToErr(err: usize) PosixExecveError {
415 assert(err > 0);426 assert(err > 0);
416 return switch (err) {427 return switch (err) {
417 posix.EFAULT => unreachable,428 posix.EFAULT => unreachable,
...@@ -904,24 +915,68 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) !void {...@@ -904,24 +915,68 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) !void {
904/// removes it. If it cannot be removed because it is a non-empty directory,915/// removes it. If it cannot be removed because it is a non-empty directory,
905/// this function recursively removes its entries and then tries again.916/// this function recursively removes its entries and then tries again.
906// TODO non-recursive implementation917// TODO non-recursive implementation
907pub fn deleteTree(allocator: &Allocator, full_path: []const u8) !void {918const DeleteTreeError = error {
919 OutOfMemory,
920 AccessDenied,
921 FileTooBig,
922 IsDir,
923 SymLinkLoop,
924 ProcessFdQuotaExceeded,
925 NameTooLong,
926 SystemFdQuotaExceeded,
927 NoDevice,
928 PathNotFound,
929 SystemResources,
930 NoSpaceLeft,
931 PathAlreadyExists,
932 ReadOnlyFileSystem,
933 NotDir,
934 FileNotFound,
935 FileSystem,
936 FileBusy,
937 DirNotEmpty,
938 Unexpected,
939};
940pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!void {
908 start_over: while (true) {941 start_over: while (true) {
909 // First, try deleting the item as a file. This way we don't follow sym links.942 // First, try deleting the item as a file. This way we don't follow sym links.
910 if (deleteFile(allocator, full_path)) {943 if (deleteFile(allocator, full_path)) {
911 return;944 return;
912 } else |err| {945 } else |err| switch (err) {
913 if (err == error.FileNotFound)946 error.FileNotFound => return,
914 return;947 error.IsDir => {},
915 if (err != error.IsDir)948
916 return err;949 error.OutOfMemory,
950 error.AccessDenied,
951 error.SymLinkLoop,
952 error.NameTooLong,
953 error.SystemResources,
954 error.ReadOnlyFileSystem,
955 error.NotDir,
956 error.FileSystem,
957 error.FileBusy,
958 error.Unexpected
959 => return err,
917 }960 }
918 {961 {
919 var dir = Dir.open(allocator, full_path) catch |err| {962 var dir = Dir.open(allocator, full_path) catch |err| switch (err) {
920 if (err == error.FileNotFound)963 error.NotDir => continue :start_over,
921 return;964
922 if (err == error.NotDir)965 error.OutOfMemory,
923 continue :start_over;966 error.AccessDenied,
924 return err;967 error.FileTooBig,
968 error.IsDir,
969 error.SymLinkLoop,
970 error.ProcessFdQuotaExceeded,
971 error.NameTooLong,
972 error.SystemFdQuotaExceeded,
973 error.NoDevice,
974 error.PathNotFound,
975 error.SystemResources,
976 error.NoSpaceLeft,
977 error.PathAlreadyExists,
978 error.Unexpected
979 => return err,
925 };980 };
926 defer dir.close();981 defer dir.close();
927982
...@@ -1252,6 +1307,8 @@ pub const ArgIteratorWindows = struct {...@@ -1252,6 +1307,8 @@ pub const ArgIteratorWindows = struct {
1252 quote_count: usize,1307 quote_count: usize,
1253 seen_quote_count: usize,1308 seen_quote_count: usize,
12541309
1310 pub const NextError = error{OutOfMemory};
1311
1255 pub fn init() ArgIteratorWindows {1312 pub fn init() ArgIteratorWindows {
1256 return initWithCmdLine(windows.GetCommandLineA());1313 return initWithCmdLine(windows.GetCommandLineA());
1257 }1314 }
...@@ -1267,7 +1324,7 @@ pub const ArgIteratorWindows = struct {...@@ -1267,7 +1324,7 @@ pub const ArgIteratorWindows = struct {
1267 }1324 }
12681325
1269 /// You must free the returned memory when done.1326 /// You must free the returned memory when done.
1270 pub fn next(self: &ArgIteratorWindows, allocator: &Allocator) ?(@typeOf(internalNext).ReturnType.ErrorSet![]u8) {1327 pub fn next(self: &ArgIteratorWindows, allocator: &Allocator) ?(NextError![]u8) {
1271 // march forward over whitespace1328 // march forward over whitespace
1272 while (true) : (self.index += 1) {1329 while (true) : (self.index += 1) {
1273 const byte = self.cmd_line[self.index];1330 const byte = self.cmd_line[self.index];
...@@ -1320,7 +1377,7 @@ pub const ArgIteratorWindows = struct {...@@ -1320,7 +1377,7 @@ pub const ArgIteratorWindows = struct {
1320 }1377 }
1321 }1378 }
13221379
1323 fn internalNext(self: &ArgIteratorWindows, allocator: &Allocator) ![]u8 {1380 fn internalNext(self: &ArgIteratorWindows, allocator: &Allocator) NextError![]u8 {
1324 var buf = try Buffer.initSize(allocator, 0);1381 var buf = try Buffer.initSize(allocator, 0);
1325 defer buf.deinit();1382 defer buf.deinit();
13261383
...@@ -1394,16 +1451,20 @@ pub const ArgIteratorWindows = struct {...@@ -1394,16 +1451,20 @@ pub const ArgIteratorWindows = struct {
1394};1451};
13951452
1396pub const ArgIterator = struct {1453pub const ArgIterator = struct {
1397 inner: if (builtin.os == Os.windows) ArgIteratorWindows else ArgIteratorPosix,1454 const InnerType = if (builtin.os == Os.windows) ArgIteratorWindows else ArgIteratorPosix;
1455
1456 inner: InnerType,
13981457
1399 pub fn init() ArgIterator {1458 pub fn init() ArgIterator {
1400 return ArgIterator {1459 return ArgIterator {
1401 .inner = if (builtin.os == Os.windows) ArgIteratorWindows.init() else ArgIteratorPosix.init(),1460 .inner = InnerType.init(),
1402 };1461 };
1403 }1462 }
1463
1464 pub const NextError = ArgIteratorWindows.NextError;
1404 1465
1405 /// You must free the returned memory when done.1466 /// You must free the returned memory when done.
1406 pub fn next(self: &ArgIterator, allocator: &Allocator) ?![]u8 {1467 pub fn next(self: &ArgIterator, allocator: &Allocator) ?(NextError![]u8) {
1407 if (builtin.os == Os.windows) {1468 if (builtin.os == Os.windows) {
1408 return self.inner.next(allocator);1469 return self.inner.next(allocator);
1409 } else {1470 } else {
std/os/windows/util.zig+2-1
...@@ -30,7 +30,6 @@ pub fn windowsClose(handle: windows.HANDLE) void {...@@ -30,7 +30,6 @@ pub fn windowsClose(handle: windows.HANDLE) void {
30pub const WriteError = error {30pub const WriteError = error {
31 SystemResources,31 SystemResources,
32 OperationAborted,32 OperationAborted,
33 SystemResources,
34 IoPending,33 IoPending,
35 BrokenPipe,34 BrokenPipe,
36 Unexpected,35 Unexpected,
...@@ -83,6 +82,8 @@ pub const OpenError = error {...@@ -83,6 +82,8 @@ pub const OpenError = error {
83 AccessDenied,82 AccessDenied,
84 PipeBusy,83 PipeBusy,
85 Unexpected,84 Unexpected,
85 OutOfMemory,
86 NameTooLong,
86};87};
8788
88/// `file_path` may need to be copied in memory to add a null terminating byte. In this case89/// `file_path` may need to be copied in memory to add a null terminating byte. In this case
std/special/bootstrap.zig+2-2
...@@ -77,7 +77,7 @@ fn callMain() u8 {...@@ -77,7 +77,7 @@ fn callMain() u8 {
77 },77 },
78 builtin.TypeId.Int => {78 builtin.TypeId.Int => {
79 if (@typeOf(root.main).ReturnType.bit_count != 8) {79 if (@typeOf(root.main).ReturnType.bit_count != 8) {
80 @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '%void'");80 @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'");
81 }81 }
82 return root.main();82 return root.main();
83 },83 },
...@@ -91,6 +91,6 @@ fn callMain() u8 {...@@ -91,6 +91,6 @@ fn callMain() u8 {
91 };91 };
92 return 0;92 return 0;
93 },93 },
94 else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '%void'"),94 else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"),
95 }95 }
96}96}
std/special/build_runner.zig+18-7
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const root = @import("@build");1const root = @import("@build");
2const std = @import("std");2const std = @import("std");
3const builtin = @import("builtin");
3const io = std.io;4const io = std.io;
4const fmt = std.fmt;5const fmt = std.fmt;
5const os = std.os;6const os = std.os;
...@@ -43,14 +44,14 @@ pub fn main() !void {...@@ -43,14 +44,14 @@ pub fn main() !void {
4344
44 var stderr_file = io.getStdErr();45 var stderr_file = io.getStdErr();
45 var stderr_file_stream: io.FileOutStream = undefined;46 var stderr_file_stream: io.FileOutStream = undefined;
46 var stderr_stream: %&io.OutStream = if (stderr_file) |*f| x: {47 var stderr_stream = if (stderr_file) |*f| x: {
47 stderr_file_stream = io.FileOutStream.init(f);48 stderr_file_stream = io.FileOutStream.init(f);
48 break :x &stderr_file_stream.stream;49 break :x &stderr_file_stream.stream;
49 } else |err| err;50 } else |err| err;
5051
51 var stdout_file = io.getStdOut();52 var stdout_file = io.getStdOut();
52 var stdout_file_stream: io.FileOutStream = undefined;53 var stdout_file_stream: io.FileOutStream = undefined;
53 var stdout_stream: %&io.OutStream = if (stdout_file) |*f| x: {54 var stdout_stream = if (stdout_file) |*f| x: {
54 stdout_file_stream = io.FileOutStream.init(f);55 stdout_file_stream = io.FileOutStream.init(f);
55 break :x &stdout_file_stream.stream;56 break :x &stdout_file_stream.stream;
56 } else |err| err;57 } else |err| err;
...@@ -110,7 +111,7 @@ pub fn main() !void {...@@ -110,7 +111,7 @@ pub fn main() !void {
110 }111 }
111112
112 builder.setInstallPrefix(prefix);113 builder.setInstallPrefix(prefix);
113 try root.build(&builder);114 try runBuild(&builder);
114115
115 if (builder.validateUserInputDidItFail())116 if (builder.validateUserInputDidItFail())
116 return usageAndErr(&builder, true, try stderr_stream);117 return usageAndErr(&builder, true, try stderr_stream);
...@@ -123,11 +124,19 @@ pub fn main() !void {...@@ -123,11 +124,19 @@ pub fn main() !void {
123 };124 };
124}125}
125126
126fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) !void {127fn runBuild(builder: &Builder) error!void {
128 switch (@typeId(@typeOf(root.build).ReturnType)) {
129 builtin.TypeId.Void => root.build(builder),
130 builtin.TypeId.ErrorUnion => try root.build(builder),
131 else => @compileError("expected return type of build to be 'void' or '!void'"),
132 }
133}
134
135fn usage(builder: &Builder, already_ran_build: bool, out_stream: var) !void {
127 // run the build script to collect the options136 // run the build script to collect the options
128 if (!already_ran_build) {137 if (!already_ran_build) {
129 builder.setInstallPrefix(null);138 builder.setInstallPrefix(null);
130 try root.build(builder);139 try runBuild(builder);
131 }140 }
132141
133 // This usage text has to be synchronized with src/main.cpp142 // This usage text has to be synchronized with src/main.cpp
...@@ -181,12 +190,14 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)...@@ -181,12 +190,14 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)
181 );190 );
182}191}
183192
184fn usageAndErr(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) error {193fn usageAndErr(builder: &Builder, already_ran_build: bool, out_stream: var) error {
185 usage(builder, already_ran_build, out_stream) catch {};194 usage(builder, already_ran_build, out_stream) catch {};
186 return error.InvalidArgs;195 return error.InvalidArgs;
187}196}
188197
189fn unwrapArg(arg: %[]u8) ![]u8 {198const UnwrapArgError = error {OutOfMemory};
199
200fn unwrapArg(arg: UnwrapArgError![]u8) UnwrapArgError![]u8 {
190 return arg catch |err| {201 return arg catch |err| {
191 warn("Unable to parse command line: {}\n", err);202 warn("Unable to parse command line: {}\n", err);
192 return err;203 return err;
test/cases/error.zig+36-2
...@@ -1,5 +1,7 @@...@@ -1,5 +1,7 @@
1const assert = @import("std").debug.assert;1const std = @import("std");
2const mem = @import("std").mem;2const assert = std.debug.assert;
3const mem = std.mem;
4const builtin = @import("builtin");
35
4pub fn foo() error!i32 {6pub fn foo() error!i32 {
5 const x = try bar();7 const x = try bar();
...@@ -74,3 +76,35 @@ fn doErrReturnInAssignment() error!void {...@@ -74,3 +76,35 @@ fn doErrReturnInAssignment() error!void {
74fn makeANonErr() error!i32 {76fn makeANonErr() error!i32 {
75 return 1;77 return 1;
76}78}
79
80test "error union type " {
81 testErrorUnionType();
82 comptime testErrorUnionType();
83}
84
85fn testErrorUnionType() void {
86 const x: error!i32 = 1234;
87 if (x) |value| assert(value == 1234) else |_| unreachable;
88 assert(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion);
89 assert(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet);
90 assert(@typeOf(x).ErrorSet == error);
91}
92
93test "error set type " {
94 testErrorSetType();
95 comptime testErrorSetType();
96}
97
98const MyErrSet = error {OutOfMemory, FileNotFound};
99
100fn testErrorSetType() void {
101 assert(@memberCount(MyErrSet) == 2);
102
103 const a: MyErrSet!i32 = 5678;
104 const b: MyErrSet!i32 = MyErrSet.OutOfMemory;
105
106 if (a) |value| assert(value == 5678) else |err| switch (err) {
107 error.OutOfMemory => unreachable,
108 error.FileNotFound => unreachable,
109 }
110}
test/compare_output.zig+12-13
...@@ -15,7 +15,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -15,7 +15,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
15 \\use @import("std").io;15 \\use @import("std").io;
16 \\use @import("foo.zig");16 \\use @import("foo.zig");
17 \\17 \\
18 \\pub fn main() !void {18 \\pub fn main() void {
19 \\ privateFunction();19 \\ privateFunction();
20 \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);20 \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);
21 \\ stdout.print("OK 2\n") catch unreachable;21 \\ stdout.print("OK 2\n") catch unreachable;
...@@ -49,7 +49,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -49,7 +49,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
49 \\use @import("foo.zig");49 \\use @import("foo.zig");
50 \\use @import("bar.zig");50 \\use @import("bar.zig");
51 \\51 \\
52 \\pub fn main() !void {52 \\pub fn main() void {
53 \\ foo_function();53 \\ foo_function();
54 \\ bar_function();54 \\ bar_function();
55 \\}55 \\}
...@@ -89,7 +89,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -89,7 +89,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
89 var tc = cases.create("two files use import each other",89 var tc = cases.create("two files use import each other",
90 \\use @import("a.zig");90 \\use @import("a.zig");
91 \\91 \\
92 \\pub fn main() !void {92 \\pub fn main() void {
93 \\ ok();93 \\ ok();
94 \\}94 \\}
95 , "OK\n");95 , "OK\n");
...@@ -118,7 +118,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -118,7 +118,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
118 cases.add("hello world without libc",118 cases.add("hello world without libc",
119 \\const io = @import("std").io;119 \\const io = @import("std").io;
120 \\120 \\
121 \\pub fn main() !void {121 \\pub fn main() void {
122 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);122 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
123 \\ stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;123 \\ stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;
124 \\}124 \\}
...@@ -268,7 +268,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -268,7 +268,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
268 \\const z = io.stdin_fileno;268 \\const z = io.stdin_fileno;
269 \\const x : @typeOf(y) = 1234;269 \\const x : @typeOf(y) = 1234;
270 \\const y : u16 = 5678;270 \\const y : u16 = 5678;
271 \\pub fn main() !void {271 \\pub fn main() void {
272 \\ var x_local : i32 = print_ok(x);272 \\ var x_local : i32 = print_ok(x);
273 \\}273 \\}
274 \\fn print_ok(val: @typeOf(x)) @typeOf(foo) {274 \\fn print_ok(val: @typeOf(x)) @typeOf(foo) {
...@@ -351,7 +351,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -351,7 +351,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
351 \\ fn method(b: &const Bar) bool { return true; }351 \\ fn method(b: &const Bar) bool { return true; }
352 \\};352 \\};
353 \\353 \\
354 \\pub fn main() !void {354 \\pub fn main() void {
355 \\ const bar = Bar {.field2 = 13,};355 \\ const bar = Bar {.field2 = 13,};
356 \\ const foo = Foo {.field1 = bar,};356 \\ const foo = Foo {.field1 = bar,};
357 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);357 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
...@@ -367,7 +367,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -367,7 +367,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
367367
368 cases.add("defer with only fallthrough",368 cases.add("defer with only fallthrough",
369 \\const io = @import("std").io;369 \\const io = @import("std").io;
370 \\pub fn main() !void {370 \\pub fn main() void {
371 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);371 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
372 \\ stdout.print("before\n") catch unreachable;372 \\ stdout.print("before\n") catch unreachable;
373 \\ defer stdout.print("defer1\n") catch unreachable;373 \\ defer stdout.print("defer1\n") catch unreachable;
...@@ -380,7 +380,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -380,7 +380,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
380 cases.add("defer with return",380 cases.add("defer with return",
381 \\const io = @import("std").io;381 \\const io = @import("std").io;
382 \\const os = @import("std").os;382 \\const os = @import("std").os;
383 \\pub fn main() !void {383 \\pub fn main() void {
384 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);384 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
385 \\ stdout.print("before\n") catch unreachable;385 \\ stdout.print("before\n") catch unreachable;
386 \\ defer stdout.print("defer1\n") catch unreachable;386 \\ defer stdout.print("defer1\n") catch unreachable;
...@@ -394,7 +394,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -394,7 +394,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
394394
395 cases.add("errdefer and it fails",395 cases.add("errdefer and it fails",
396 \\const io = @import("std").io;396 \\const io = @import("std").io;
397 \\pub fn main() !void {397 \\pub fn main() void {
398 \\ do_test() catch return;398 \\ do_test() catch return;
399 \\}399 \\}
400 \\fn do_test() !void {400 \\fn do_test() !void {
...@@ -406,7 +406,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -406,7 +406,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
406 \\ defer stdout.print("defer3\n") catch unreachable;406 \\ defer stdout.print("defer3\n") catch unreachable;
407 \\ stdout.print("after\n") catch unreachable;407 \\ stdout.print("after\n") catch unreachable;
408 \\}408 \\}
409 \\error IToldYouItWouldFail;
410 \\fn its_gonna_fail() !void {409 \\fn its_gonna_fail() !void {
411 \\ return error.IToldYouItWouldFail;410 \\ return error.IToldYouItWouldFail;
412 \\}411 \\}
...@@ -414,7 +413,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -414,7 +413,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
414413
415 cases.add("errdefer and it passes",414 cases.add("errdefer and it passes",
416 \\const io = @import("std").io;415 \\const io = @import("std").io;
417 \\pub fn main() !void {416 \\pub fn main() void {
418 \\ do_test() catch return;417 \\ do_test() catch return;
419 \\}418 \\}
420 \\fn do_test() !void {419 \\fn do_test() !void {
...@@ -426,7 +425,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -426,7 +425,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
426 \\ defer stdout.print("defer3\n") catch unreachable;425 \\ defer stdout.print("defer3\n") catch unreachable;
427 \\ stdout.print("after\n") catch unreachable;426 \\ stdout.print("after\n") catch unreachable;
428 \\}427 \\}
429 \\fn its_gonna_pass() %void { }428 \\fn its_gonna_pass() error!void { }
430 , "before\nafter\ndefer3\ndefer1\n");429 , "before\nafter\ndefer3\ndefer1\n");
431430
432 cases.addCase(x: {431 cases.addCase(x: {
...@@ -434,7 +433,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -434,7 +433,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
434 \\const foo_txt = @embedFile("foo.txt");433 \\const foo_txt = @embedFile("foo.txt");
435 \\const io = @import("std").io;434 \\const io = @import("std").io;
436 \\435 \\
437 \\pub fn main() !void {436 \\pub fn main() void {
438 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);437 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
439 \\ stdout.print(foo_txt) catch unreachable;438 \\ stdout.print(foo_txt) catch unreachable;
440 \\}439 \\}
test/compile_errors.zig+33-15
...@@ -1,6 +1,25 @@...@@ -1,6 +1,25 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.CompileErrorContext) void {3pub fn addCases(cases: &tests.CompileErrorContext) void {
4 cases.add("@memberCount of error",
5 \\comptime {
6 \\ _ = @memberCount(error);
7 \\}
8 ,
9 ".tmp_source.zig:2:9: error: global error set member count not available at comptime");
10
11 cases.add("duplicate error value in error set",
12 \\const Foo = error {
13 \\ Bar,
14 \\ Bar,
15 \\};
16 \\export fn entry() void {
17 \\ const a: Foo = undefined;
18 \\}
19 ,
20 ".tmp_source.zig:3:5: error: duplicate error: 'Bar'",
21 ".tmp_source.zig:2:5: note: other error here");
22
4 cases.add("duplicate struct field",23 cases.add("duplicate struct field",
5 \\const Foo = struct {24 \\const Foo = struct {
6 \\ Bar: i32,25 \\ Bar: i32,
...@@ -99,12 +118,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -99,12 +118,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
99118
100 cases.add("wrong return type for main",119 cases.add("wrong return type for main",
101 \\pub fn main() f32 { }120 \\pub fn main() f32 { }
102 , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '%void'");121 , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '!void'");
103122
104 cases.add("double ?? on main return value",123 cases.add("double ?? on main return value",
105 \\pub fn main() ??void {124 \\pub fn main() ??void {
106 \\}125 \\}
107 , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '%void'");126 , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '!void'");
108127
109 cases.add("bad identifier in function with struct defined inside function which references local const",128 cases.add("bad identifier in function with struct defined inside function which references local const",
110 \\export fn entry() void {129 \\export fn entry() void {
...@@ -1160,7 +1179,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1160,7 +1179,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1160 \\export fn f() void {1179 \\export fn f() void {
1161 \\ try something();1180 \\ try something();
1162 \\}1181 \\}
1163 \\fn something() %void { }1182 \\fn something() error!void { }
1164 ,1183 ,
1165 ".tmp_source.zig:2:5: error: expected type 'void', found 'error'");1184 ".tmp_source.zig:2:5: error: expected type 'void', found 'error'");
11661185
...@@ -1251,7 +1270,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1251,7 +1270,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1251 , ".tmp_source.zig:3:11: error: cannot assign to constant");1270 , ".tmp_source.zig:3:11: error: cannot assign to constant");
12521271
1253 cases.add("main function with bogus args type",1272 cases.add("main function with bogus args type",
1254 \\pub fn main(args: [][]bogus) %void {}1273 \\pub fn main(args: [][]bogus) !void {}
1255 , ".tmp_source.zig:1:23: error: use of undeclared identifier 'bogus'");1274 , ".tmp_source.zig:1:23: error: use of undeclared identifier 'bogus'");
12561275
1257 cases.add("for loop missing element param",1276 cases.add("for loop missing element param",
...@@ -1391,7 +1410,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1391,7 +1410,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1391 \\ const a = maybeInt() ?? return;1410 \\ const a = maybeInt() ?? return;
1392 \\}1411 \\}
1393 \\1412 \\
1394 \\fn canFail() %void { }1413 \\fn canFail() error!void { }
1395 \\1414 \\
1396 \\pub fn maybeInt() ?i32 {1415 \\pub fn maybeInt() ?i32 {
1397 \\ return 0;1416 \\ return 0;
...@@ -1521,7 +1540,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1521,7 +1540,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1521 \\export fn foo() void {1540 \\export fn foo() void {
1522 \\ bar() catch unreachable;1541 \\ bar() catch unreachable;
1523 \\}1542 \\}
1524 \\fn bar() %i32 { return 0; }1543 \\fn bar() error!i32 { return 0; }
1525 , ".tmp_source.zig:2:11: error: expression value is ignored");1544 , ".tmp_source.zig:2:11: error: expression value is ignored");
15261545
1527 cases.add("ignored statement value",1546 cases.add("ignored statement value",
...@@ -1552,7 +1571,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1552,7 +1571,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1552 \\export fn foo() void {1571 \\export fn foo() void {
1553 \\ defer bar();1572 \\ defer bar();
1554 \\}1573 \\}
1555 \\fn bar() %i32 { return 0; }1574 \\fn bar() error!i32 { return 0; }
1556 , ".tmp_source.zig:2:14: error: expression value is ignored");1575 , ".tmp_source.zig:2:14: error: expression value is ignored");
15571576
1558 cases.add("dereference an array",1577 cases.add("dereference an array",
...@@ -1619,13 +1638,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1619,13 +1638,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1619 , ".tmp_source.zig:2:21: error: expected pointer, found 'usize'");1638 , ".tmp_source.zig:2:21: error: expected pointer, found 'usize'");
16201639
1621 cases.add("too many error values to cast to small integer",1640 cases.add("too many error values to cast to small integer",
1622 \\error A; error B; error C; error D; error E; error F; error G; error H;1641 \\const Error = error { A, B, C, D, E, F, G, H };
1623 \\const u2 = @IntType(false, 2);1642 \\fn foo(e: Error) u2 {
1624 \\fn foo(e: error) u2 {
1625 \\ return u2(e);1643 \\ return u2(e);
1626 \\}1644 \\}
1627 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }1645 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
1628 , ".tmp_source.zig:4:14: error: too many error values to fit in 'u2'");1646 , ".tmp_source.zig:3:14: error: too many error values to fit in 'u2'");
16291647
1630 cases.add("asm at compile time",1648 cases.add("asm at compile time",
1631 \\comptime {1649 \\comptime {
...@@ -1808,9 +1826,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1808,9 +1826,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1808 \\export fn foo() void {1826 \\export fn foo() void {
1809 \\ while (bar()) {}1827 \\ while (bar()) {}
1810 \\}1828 \\}
1811 \\fn bar() %i32 { return 1; }1829 \\fn bar() error!i32 { return 1; }
1812 ,1830 ,
1813 ".tmp_source.zig:2:15: error: expected type 'bool', found '%i32'");1831 ".tmp_source.zig:2:15: error: expected type 'bool', found 'error!i32'");
18141832
1815 cases.add("while expected nullable, got bool",1833 cases.add("while expected nullable, got bool",
1816 \\export fn foo() void {1834 \\export fn foo() void {
...@@ -1824,9 +1842,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1824,9 +1842,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1824 \\export fn foo() void {1842 \\export fn foo() void {
1825 \\ while (bar()) |x| {}1843 \\ while (bar()) |x| {}
1826 \\}1844 \\}
1827 \\fn bar() %i32 { return 1; }1845 \\fn bar() error!i32 { return 1; }
1828 ,1846 ,
1829 ".tmp_source.zig:2:15: error: expected nullable type, found '%i32'");1847 ".tmp_source.zig:2:15: error: expected nullable type, found 'error!i32'");
18301848
1831 cases.add("while expected error union, got bool",1849 cases.add("while expected error union, got bool",
1832 \\export fn foo() void {1850 \\export fn foo() void {
test/standalone/brace_expansion/build.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) !void {3pub fn build(b: &Builder) void {
4 const main = b.addTest("main.zig");4 const main = b.addTest("main.zig");
5 main.setBuildMode(b.standardReleaseOptions());5 main.setBuildMode(b.standardReleaseOptions());
66
test/standalone/brace_expansion/main.zig+11-2
...@@ -68,7 +68,12 @@ const Node = union(enum) {...@@ -68,7 +68,12 @@ const Node = union(enum) {
68 Combine: []Node,68 Combine: []Node,
69};69};
7070
71fn parse(tokens: &const ArrayList(Token), token_index: &usize) !Node {71const ParseError = error {
72 InvalidInput,
73 OutOfMemory,
74};
75
76fn parse(tokens: &const ArrayList(Token), token_index: &usize) ParseError!Node {
72 const first_token = tokens.items[*token_index];77 const first_token = tokens.items[*token_index];
73 *token_index += 1;78 *token_index += 1;
7479
...@@ -132,7 +137,11 @@ fn expandString(input: []const u8, output: &Buffer) !void {...@@ -132,7 +137,11 @@ fn expandString(input: []const u8, output: &Buffer) !void {
132 }137 }
133}138}
134139
135fn expandNode(node: &const Node, output: &ArrayList(Buffer)) !void {140const ExpandNodeError = error {
141 OutOfMemory,
142};
143
144fn expandNode(node: &const Node, output: &ArrayList(Buffer)) ExpandNodeError!void {
136 assert(output.len == 0);145 assert(output.len == 0);
137 switch (*node) {146 switch (*node) {
138 Node.Scalar => |scalar| {147 Node.Scalar => |scalar| {
test/standalone/issue_339/build.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) !void {3pub fn build(b: &Builder) void {
4 const obj = b.addObject("test", "test.zig");4 const obj = b.addObject("test", "test.zig");
55
6 const test_step = b.step("test", "Test the program");6 const test_step = b.step("test", "Test the program");
test/standalone/issue_339/test.zig+1-1
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const StackTrace = @import("builtin").StackTrace;1const StackTrace = @import("builtin").StackTrace;
2pub fn panic(msg: []const u8, stack_trace: ?&StackTrace) noreturn { @breakpoint(); while (true) {} }2pub fn panic(msg: []const u8, stack_trace: ?&StackTrace) noreturn { @breakpoint(); while (true) {} }
33
4fn bar() %void {}4fn bar() error!void {}
55
6export fn foo() void {6export fn foo() void {
7 bar() catch unreachable;7 bar() catch unreachable;
test/standalone/pkg_import/build.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) !void {3pub fn build(b: &Builder) void {
4 const exe = b.addExecutable("test", "test.zig");4 const exe = b.addExecutable("test", "test.zig");
5 exe.addPackagePath("my_pkg", "pkg.zig");5 exe.addPackagePath("my_pkg", "pkg.zig");
66
test/standalone/pkg_import/test.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const my_pkg = @import("my_pkg");1const my_pkg = @import("my_pkg");
2const assert = @import("std").debug.assert;2const assert = @import("std").debug.assert;
33
4pub fn main() !void {4pub fn main() void {
5 assert(my_pkg.add(10, 20) == 30);5 assert(my_pkg.add(10, 20) == 30);
6}6}
test/standalone/use_alias/build.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) !void {3pub fn build(b: &Builder) void {
4 b.addCIncludePath(".");4 b.addCIncludePath(".");
55
6 const main = b.addTest("main.zig");6 const main = b.addTest("main.zig");