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 @@
11sed -i 's/\(\bfn .*) \)%\(.*{\)$/\1!\2/g' $(find . -name "*.zig")
22
3
34the literal translation of `%T` to this new code is `error!T`.
45however this would not take advantage of error sets. It's
56recommended to generally have all your functions which return possible
......@@ -11,6 +12,11 @@ fn foo() !void {
1112
1213then 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
1420// TODO this is an explicit cast and should actually coerce the type
1521 erorr set casting
1622
......@@ -27,3 +33,8 @@ comptime test for err
2733undefined in infer error
2834
2935syntax - ?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 {
4242 const input_file_bytes = try file_in_stream.stream.readAllAlloc(allocator, max_doc_file_size);
4343
4444 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
4747 var tokenizer = Tokenizer.init(in_file_name, input_file_bytes);
4848 var toc = try genToc(allocator, &tokenizer);
......@@ -218,8 +218,6 @@ const Tokenizer = struct {
218218 }
219219};
220220
221error ParseError;
222
223221fn parseError(tokenizer: &Tokenizer, token: &const Token, comptime fmt: []const u8, args: ...) error {
224222 const loc = tokenizer.getTokenLocation(token);
225223 warn("{}:{}:{}: error: " ++ fmt ++ "\n", tokenizer.source_file_name, loc.line + 1, loc.column + 1, args);
......@@ -596,8 +594,6 @@ const TermState = enum {
596594 ExpectEnd,
597595};
598596
599error UnsupportedEscape;
600
601597test "term color" {
602598 const input_bytes = "A\x1b[32;1mgreen\x1b[0mB";
603599 const result = try termColor(std.debug.global_allocator, input_bytes);
......@@ -684,9 +680,7 @@ fn termColor(allocator: &mem.Allocator, input: []const u8) ![]u8 {
684680 return buf.toOwnedSlice();
685681}
686682
687error ExampleFailedToCompile;
688
689fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io.OutStream, zig_exe: []const u8) !void {
683fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var, zig_exe: []const u8) !void {
690684 var code_progress_index: usize = 0;
691685 for (toc.nodes) |node| {
692686 switch (node) {
......@@ -974,9 +968,6 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io
974968
975969}
976970
977error ChildCrashed;
978error ChildExitError;
979
980971fn exec(allocator: &mem.Allocator, args: []const []const u8) !os.ChildProcess.ExecResult {
981972 const result = try os.ChildProcess.exec(allocator, args, null, null, max_doc_file_size);
982973 switch (result.term) {
example/cat/main.zig+1-1
......@@ -61,7 +61,7 @@ fn cat_file(stdout: &io.File, file: &io.File) !void {
6161 }
6262}
6363
64fn unwrapArg(arg: %[]u8) ![]u8 {
64fn unwrapArg(arg: error![]u8) ![]u8 {
6565 return arg catch |err| {
6666 warn("Unable to parse command line: {}\n", err);
6767 return err;
example/mix_o_files/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) !void {
3pub fn build(b: &Builder) void {
44 const obj = b.addObject("base64", "base64.zig");
55
66 const exe = b.addCExecutable("test");
example/shared_library/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) !void {
3pub fn build(b: &Builder) void {
44 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
55
66 const exe = b.addCExecutable("test");
src-self-hosted/main.zig+1-5
......@@ -14,10 +14,6 @@ const builtin = @import("builtin");
1414const ArrayList = std.ArrayList;
1515const c = @import("c.zig");
1616
17error InvalidCommandLineArguments;
18error ZigLibDirNotFound;
19error ZigInstallationNotFound;
20
2117const default_zig_cache_name = "zig-cache";
2218
2319pub fn main() !void {
......@@ -472,7 +468,7 @@ pub fn main2() !void {
472468 }
473469}
474470
475fn printUsage(stream: &io.OutStream) !void {
471fn printUsage(stream: var) !void {
476472 try stream.write(
477473 \\Usage: zig [command] [options]
478474 \\
src-self-hosted/module.zig+2-1
......@@ -110,7 +110,7 @@ pub const Module = struct {
110110 };
111111
112112 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) %&Module
113 kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !&Module
114114 {
115115 var name_buffer = try Buffer.init(allocator, name);
116116 errdefer name_buffer.deinit();
......@@ -265,6 +265,7 @@ pub const Module = struct {
265265
266266 pub fn link(self: &Module, out_file: ?[]const u8) !void {
267267 warn("TODO link");
268 return error.Todo;
268269 }
269270
270271 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;
1212// get rid of this
1313const warn = std.debug.warn;
1414
15error ParseError;
16
1715pub const Parser = struct {
1816 allocator: &mem.Allocator,
1917 tokenizer: &Tokenizer,
......@@ -555,7 +553,7 @@ pub const Parser = struct {
555553 }
556554
557555 fn createVarDecl(self: &Parser, visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token,
558 extern_token: &const ?Token) %&ast.NodeVarDecl
556 extern_token: &const ?Token) !&ast.NodeVarDecl
559557 {
560558 const node = try self.allocator.create(ast.NodeVarDecl);
561559
......@@ -577,7 +575,7 @@ pub const Parser = struct {
577575 }
578576
579577 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.NodeFnProto
578 cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) !&ast.NodeFnProto
581579 {
582580 const node = try self.allocator.create(ast.NodeFnProto);
583581
......@@ -694,7 +692,7 @@ pub const Parser = struct {
694692
695693 fn createAttachFnProto(self: &Parser, list: &ArrayList(&ast.Node), fn_token: &const Token,
696694 extern_token: &const ?Token, cc_token: &const ?Token, visib_token: &const ?Token,
697 inline_token: &const ?Token) %&ast.NodeFnProto
695 inline_token: &const ?Token) !&ast.NodeFnProto
698696 {
699697 const node = try self.createFnProto(fn_token, extern_token, cc_token, visib_token, inline_token);
700698 try list.append(&node.base);
......@@ -702,7 +700,7 @@ pub const Parser = struct {
702700 }
703701
704702 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.NodeVarDecl
703 mut_token: &const Token, comptime_token: &const ?Token, extern_token: &const ?Token) !&ast.NodeVarDecl
706704 {
707705 const node = try self.createVarDecl(visib_token, mut_token, comptime_token, extern_token);
708706 try list.append(&node.base);
......@@ -763,7 +761,7 @@ pub const Parser = struct {
763761 indent: usize,
764762 };
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 {
767765 var stack = self.initUtilityArrayList(RenderAstFrame);
768766 defer self.deinitUtilityArrayList(stack);
769767
......@@ -802,7 +800,7 @@ pub const Parser = struct {
802800 Indent: usize,
803801 };
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 {
806804 var stack = self.initUtilityArrayList(RenderState);
807805 defer self.deinitUtilityArrayList(stack);
808806
......@@ -1058,10 +1056,6 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {
10581056 return buffer.toOwnedSlice();
10591057}
10601058
1061error TestFailed;
1062error NondeterministicMemoryUsage;
1063error MemoryLeakDetected;
1064
10651059// TODO test for memory leaks
10661060// TODO test for valid frees
10671061fn testCanonical(source: []const u8) !void {
src/ir.cpp+72-4
......@@ -5442,6 +5442,10 @@ static TypeTableEntry *get_error_set_union(CodeGen *g, ErrorTableEntry **errors,
54425442 buf_resize(&err_set_type->name, 0);
54435443 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
54455449 uint32_t count = set1->data.error_set.err_count;
54465450 for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) {
54475451 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
55235527 err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count);
55245528 }
55255529
5530 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(irb->codegen->errors_by_index.length + err_count);
5531
55265532 for (uint32_t i = 0; i < err_count; i += 1) {
55275533 AstNode *symbol_node = node->data.err_set_decl.decls.at(i);
55285534 assert(symbol_node->type == NodeTypeSymbol);
......@@ -5543,7 +5549,16 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A
55435549 buf_ptr(err_name), error_value_count));
55445550 }
55455551 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;
55465560 }
5561 free(errors);
55475562 return ir_build_const_type(irb, parent_scope, node, err_set_type);
55485563}
55495564
......@@ -6512,6 +6527,7 @@ static TypeTableEntry *get_error_set_intersection(IrAnalyze *ira, TypeTableEntry
65126527 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
65136528 for (uint32_t i = 0; i < set1->data.error_set.err_count; i += 1) {
65146529 ErrorTableEntry *error_entry = set1->data.error_set.errors[i];
6530 assert(errors[error_entry->value] == nullptr);
65156531 errors[error_entry->value] = error_entry;
65166532 }
65176533 ZigList<ErrorTableEntry *> intersection_list = {};
......@@ -6653,6 +6669,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
66536669 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(g->errors_by_index.length);
66546670 for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) {
66556671 ErrorTableEntry *error_entry = container_set->data.error_set.errors[i];
6672 assert(errors[error_entry->value] == nullptr);
66566673 errors[error_entry->value] = error_entry;
66576674 }
66586675 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,
67676784 buf_sprintf("unable to cast global error set into smaller set"));
67686785 return ImplicitCastMatchResultReportedError;
67696786 }
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;
67706793 }
67716794 if (missing_errors != nullptr) {
67726795 ErrorMsg *msg = ir_add_error(ira, value,
......@@ -6995,6 +7018,12 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
69957018 return ImplicitCastMatchResultNo;
69967019}
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
69987027static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) {
69997028 assert(instruction_count >= 1);
70007029 IrInstruction *prev_inst = instructions[0];
......@@ -7002,6 +7031,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
70027031 return ira->codegen->builtin_types.entry_invalid;
70037032 }
70047033 ErrorTableEntry **errors = nullptr;
7034 size_t errors_count = 0;
70057035 TypeTableEntry *err_set_type = nullptr;
70067036 if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) {
70077037 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
70117041 if (!resolve_inferred_error_set(ira, err_set_type, prev_inst->source_node)) {
70127042 return ira->codegen->builtin_types.entry_invalid;
70137043 }
7014 errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
7044 update_errors_helper(ira->codegen, &errors, &errors_count);
7045
70157046 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
70167047 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
7048 assert(errors[error_entry->value] == nullptr);
70177049 errors[error_entry->value] = error_entry;
70187050 }
70197051 }
......@@ -7064,6 +7096,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
70647096 continue;
70657097 }
70667098
7099 // number of declared errors might have increased now
7100 update_errors_helper(ira->codegen, &errors, &errors_count);
7101
70677102 // if err_set_type is a superset of cur_type, keep err_set_type.
70687103 // if cur_type is a superset of err_set_type, switch err_set_type to cur_type
70697104 bool prev_is_superset = true;
......@@ -7084,8 +7119,12 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
70847119 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
70857120 errors[error_entry->value] = nullptr;
70867121 }
7122 for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) {
7123 assert(errors[i] == nullptr);
7124 }
70877125 for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) {
70887126 ErrorTableEntry *error_entry = cur_type->data.error_set.errors[i];
7127 assert(errors[error_entry->value] == nullptr);
70897128 errors[error_entry->value] = error_entry;
70907129 }
70917130 bool cur_is_superset = true;
......@@ -7122,14 +7161,21 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
71227161 prev_inst = cur_inst;
71237162 continue;
71247163 }
7164
7165 update_errors_helper(ira->codegen, &errors, &errors_count);
7166
71257167 // test if err_set_type is a subset of cur_type's error set
71267168 // unset everything in errors
71277169 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
71287170 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
71297171 errors[error_entry->value] = nullptr;
71307172 }
7173 for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) {
7174 assert(errors[i] == nullptr);
7175 }
71317176 for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) {
71327177 ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i];
7178 assert(errors[error_entry->value] == nullptr);
71337179 errors[error_entry->value] = error_entry;
71347180 }
71357181 bool cur_is_superset = true;
......@@ -7173,15 +7219,18 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
71737219 if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) {
71747220 return ira->codegen->builtin_types.entry_invalid;
71757221 }
7222
7223 update_errors_helper(ira->codegen, &errors, &errors_count);
7224
71767225 if (err_set_type == nullptr) {
71777226 if (prev_type->id == TypeTableEntryIdErrorUnion) {
71787227 err_set_type = prev_type->data.error_union.err_set_type;
71797228 } else {
71807229 err_set_type = cur_type;
71817230 }
7182 errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
71837231 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
71847232 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
7233 assert(errors[error_entry->value] == nullptr);
71857234 errors[error_entry->value] = error_entry;
71867235 }
71877236 if (err_set_type == cur_type) {
......@@ -7237,11 +7286,13 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
72377286 continue;
72387287 }
72397288
7289 update_errors_helper(ira->codegen, &errors, &errors_count);
7290
72407291 if (err_set_type == nullptr) {
72417292 err_set_type = prev_err_set_type;
7242 errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
72437293 for (uint32_t i = 0; i < prev_err_set_type->data.error_set.err_count; i += 1) {
72447294 ErrorTableEntry *error_entry = prev_err_set_type->data.error_set.errors[i];
7295 assert(errors[error_entry->value] == nullptr);
72457296 errors[error_entry->value] = error_entry;
72467297 }
72477298 }
......@@ -7262,8 +7313,12 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
72627313 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
72637314 errors[error_entry->value] = nullptr;
72647315 }
7316 for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) {
7317 assert(errors[i] == nullptr);
7318 }
72657319 for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) {
72667320 ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i];
7321 assert(errors[error_entry->value] == nullptr);
72677322 errors[error_entry->value] = error_entry;
72687323 }
72697324 bool cur_is_superset = true;
......@@ -7331,6 +7386,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
73317386 continue;
73327387 }
73337388
7389 update_errors_helper(ira->codegen, &errors, &errors_count);
7390
73347391 err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_err_set_type);
73357392 }
73367393 prev_inst = cur_inst;
......@@ -8000,6 +8057,7 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou
80008057 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
80018058 for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) {
80028059 ErrorTableEntry *error_entry = container_set->data.error_set.errors[i];
8060 assert(errors[error_entry->value] == nullptr);
80038061 errors[error_entry->value] = error_entry;
80048062 }
80058063 ErrorMsg *err_msg = nullptr;
......@@ -10212,8 +10270,9 @@ static TypeTableEntry *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstruction
1021210270 }
1021310271
1021410272 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) {
1021610274 ErrorTableEntry *error_entry = op1_type->data.error_set.errors[i];
10275 assert(errors[error_entry->value] == nullptr);
1021710276 errors[error_entry->value] = error_entry;
1021810277 }
1021910278 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
1498715046 result = container_type->data.structure.src_field_count;
1498815047 } else if (container_type->id == TypeTableEntryIdUnion) {
1498915048 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;
1499015058 } else {
1499115059 ir_add_error(ira, &instruction->base, buf_sprintf("no value count available for type '%s'", buf_ptr(&container_type->name)));
1499215060 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) {
9292}
9393
9494template<typename T>
95static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) {
96#ifdef NDEBUG
95static inline T *reallocate(T *old, size_t old_count, size_t new_count) {
9796 T *ptr = reinterpret_cast<T*>(realloc(old, new_count * sizeof(T)));
9897 if (!ptr)
9998 zig_panic("allocation failed");
99 if (new_count > old_count) {
100 memset(&ptr[old_count], 0, (new_count - old_count) * sizeof(T));
101 }
100102 return ptr;
101#else
102 // manually assign every element to trigger compile error for non-copyable structs
103 T *ptr = allocate_nonzero<T>(new_count);
104 safe_memcpy(ptr, old, old_count);
105 free(old);
103}
104
105template<typename T>
106static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) {
107 T *ptr = reinterpret_cast<T*>(realloc(old, new_count * sizeof(T)));
108 if (!ptr)
109 zig_panic("allocation failed");
106110 return ptr;
107#endif
108111}
109112
110113template <typename T, size_t n>
std/build.zig+4-4
......@@ -271,7 +271,7 @@ pub const Builder = struct {
271271 return &self.uninstall_tls.step;
272272 }
273273
274 fn makeUninstall(uninstall_step: &Step) !void {
274 fn makeUninstall(uninstall_step: &Step) error!void {
275275 const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step);
276276 const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls);
277277
......@@ -285,7 +285,7 @@ pub const Builder = struct {
285285 // TODO remove empty directories
286286 }
287287
288 fn makeOneStep(self: &Builder, s: &Step) !void {
288 fn makeOneStep(self: &Builder, s: &Step) error!void {
289289 if (s.loop_flag) {
290290 warn("Dependency loop detected:\n {}\n", s.name);
291291 return error.DependencyLoopDetected;
......@@ -1910,7 +1910,7 @@ pub const LogStep = struct {
19101910 };
19111911 }
19121912
1913 fn make(step: &Step) !void {
1913 fn make(step: &Step) error!void {
19141914 const self = @fieldParentPtr(LogStep, "step", step);
19151915 warn("{}", self.data);
19161916 }
......@@ -1972,7 +1972,7 @@ pub const Step = struct {
19721972 self.dependencies.append(other) catch unreachable;
19731973 }
19741974
1975 fn makeNoOp(self: &Step) (error{}!void) {}
1975 fn makeNoOp(self: &Step) error!void {}
19761976};
19771977
19781978fn 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: ...
510510 return bufPrint(buf, fmt, args);
511511}
512512
513fn countSize(size: &usize, bytes: []const u8) !void {
513fn countSize(size: &usize, bytes: []const u8) (error{}!void) {
514514 *size += bytes.len;
515515}
516516
std/io.zig+2-2
......@@ -694,13 +694,13 @@ pub const BufferOutStream = struct {
694694 pub fn init(buffer: &Buffer) BufferOutStream {
695695 return BufferOutStream {
696696 .buffer = buffer,
697 .stream = OutStream {
697 .stream = Stream {
698698 .writeFn = writeFn,
699699 },
700700 };
701701 }
702702
703 fn writeFn(out_stream: &OutStream, bytes: []const u8) !void {
703 fn writeFn(out_stream: &Stream, bytes: []const u8) !void {
704704 const self = @fieldParentPtr(BufferOutStream, "stream", out_stream);
705705 return self.buffer.append(bytes);
706706 }
std/os/child_process.zig+18-3
......@@ -55,7 +55,22 @@ pub const ChildProcess = struct {
5555 llnode: if (is_windows) void else LinkedList(&ChildProcess).Node,
5656
5757 pub const SpawnError = error {
58
58 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,
5974 };
6075
6176 pub const Term = union(enum) {
......@@ -313,7 +328,7 @@ pub const ChildProcess = struct {
313328 // Here we potentially return the fork child's error
314329 // from the parent pid.
315330 if (err_int != @maxValue(ErrInt)) {
316 return error(err_int);
331 return SpawnError(err_int);
317332 }
318333
319334 return statusToTerm(status);
......@@ -757,7 +772,7 @@ fn destroyPipe(pipe: &const [2]i32) void {
757772
758773// Child of fork calls this to report an error to the fork parent.
759774// Then the child exits.
760fn forkChildErrReport(fd: i32, err: error) noreturn {
775fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
761776 _ = writeIntFd(fd, ErrInt(err));
762777 posix.exit(1);
763778}
std/os/index.zig+80-19
......@@ -243,7 +243,6 @@ pub const PosixOpenError = error {
243243 SystemResources,
244244 NoSpaceLeft,
245245 NotDir,
246 AccessDenied,
247246 PathAlreadyExists,
248247 Unexpected,
249248};
......@@ -411,7 +410,19 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,
411410 return posixExecveErrnoToErr(err);
412411}
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 {
415426 assert(err > 0);
416427 return switch (err) {
417428 posix.EFAULT => unreachable,
......@@ -904,24 +915,68 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) !void {
904915/// removes it. If it cannot be removed because it is a non-empty directory,
905916/// this function recursively removes its entries and then tries again.
906917// 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 {
908941 start_over: while (true) {
909942 // First, try deleting the item as a file. This way we don't follow sym links.
910943 if (deleteFile(allocator, full_path)) {
911944 return;
912 } else |err| {
913 if (err == error.FileNotFound)
914 return;
915 if (err != error.IsDir)
916 return err;
945 } else |err| switch (err) {
946 error.FileNotFound => return,
947 error.IsDir => {},
948
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,
917960 }
918961 {
919 var dir = Dir.open(allocator, full_path) catch |err| {
920 if (err == error.FileNotFound)
921 return;
922 if (err == error.NotDir)
923 continue :start_over;
924 return err;
962 var dir = Dir.open(allocator, full_path) catch |err| switch (err) {
963 error.NotDir => continue :start_over,
964
965 error.OutOfMemory,
966 error.AccessDenied,
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,
925980 };
926981 defer dir.close();
927982
......@@ -1252,6 +1307,8 @@ pub const ArgIteratorWindows = struct {
12521307 quote_count: usize,
12531308 seen_quote_count: usize,
12541309
1310 pub const NextError = error{OutOfMemory};
1311
12551312 pub fn init() ArgIteratorWindows {
12561313 return initWithCmdLine(windows.GetCommandLineA());
12571314 }
......@@ -1267,7 +1324,7 @@ pub const ArgIteratorWindows = struct {
12671324 }
12681325
12691326 /// 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) {
12711328 // march forward over whitespace
12721329 while (true) : (self.index += 1) {
12731330 const byte = self.cmd_line[self.index];
......@@ -1320,7 +1377,7 @@ pub const ArgIteratorWindows = struct {
13201377 }
13211378 }
13221379
1323 fn internalNext(self: &ArgIteratorWindows, allocator: &Allocator) ![]u8 {
1380 fn internalNext(self: &ArgIteratorWindows, allocator: &Allocator) NextError![]u8 {
13241381 var buf = try Buffer.initSize(allocator, 0);
13251382 defer buf.deinit();
13261383
......@@ -1394,16 +1451,20 @@ pub const ArgIteratorWindows = struct {
13941451};
13951452
13961453pub 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
13991458 pub fn init() ArgIterator {
14001459 return ArgIterator {
1401 .inner = if (builtin.os == Os.windows) ArgIteratorWindows.init() else ArgIteratorPosix.init(),
1460 .inner = InnerType.init(),
14021461 };
14031462 }
1463
1464 pub const NextError = ArgIteratorWindows.NextError;
14041465
14051466 /// 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) {
14071468 if (builtin.os == Os.windows) {
14081469 return self.inner.next(allocator);
14091470 } else {
std/os/windows/util.zig+2-1
......@@ -30,7 +30,6 @@ pub fn windowsClose(handle: windows.HANDLE) void {
3030pub const WriteError = error {
3131 SystemResources,
3232 OperationAborted,
33 SystemResources,
3433 IoPending,
3534 BrokenPipe,
3635 Unexpected,
......@@ -83,6 +82,8 @@ pub const OpenError = error {
8382 AccessDenied,
8483 PipeBusy,
8584 Unexpected,
85 OutOfMemory,
86 NameTooLong,
8687};
8788
8889/// `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 {
7777 },
7878 builtin.TypeId.Int => {
7979 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'");
8181 }
8282 return root.main();
8383 },
......@@ -91,6 +91,6 @@ fn callMain() u8 {
9191 };
9292 return 0;
9393 },
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'"),
9595 }
9696}
std/special/build_runner.zig+18-7
......@@ -1,5 +1,6 @@
11const root = @import("@build");
22const std = @import("std");
3const builtin = @import("builtin");
34const io = std.io;
45const fmt = std.fmt;
56const os = std.os;
......@@ -43,14 +44,14 @@ pub fn main() !void {
4344
4445 var stderr_file = io.getStdErr();
4546 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: {
4748 stderr_file_stream = io.FileOutStream.init(f);
4849 break :x &stderr_file_stream.stream;
4950 } else |err| err;
5051
5152 var stdout_file = io.getStdOut();
5253 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: {
5455 stdout_file_stream = io.FileOutStream.init(f);
5556 break :x &stdout_file_stream.stream;
5657 } else |err| err;
......@@ -110,7 +111,7 @@ pub fn main() !void {
110111 }
111112
112113 builder.setInstallPrefix(prefix);
113 try root.build(&builder);
114 try runBuild(&builder);
114115
115116 if (builder.validateUserInputDidItFail())
116117 return usageAndErr(&builder, true, try stderr_stream);
......@@ -123,11 +124,19 @@ pub fn main() !void {
123124 };
124125}
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 {
127136 // run the build script to collect the options
128137 if (!already_ran_build) {
129138 builder.setInstallPrefix(null);
130 try root.build(builder);
139 try runBuild(builder);
131140 }
132141
133142 // 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)
181190 );
182191}
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 {
185194 usage(builder, already_ran_build, out_stream) catch {};
186195 return error.InvalidArgs;
187196}
188197
189fn unwrapArg(arg: %[]u8) ![]u8 {
198const UnwrapArgError = error {OutOfMemory};
199
200fn unwrapArg(arg: UnwrapArgError![]u8) UnwrapArgError![]u8 {
190201 return arg catch |err| {
191202 warn("Unable to parse command line: {}\n", err);
192203 return err;
test/cases/error.zig+36-2
......@@ -1,5 +1,7 @@
1const assert = @import("std").debug.assert;
2const mem = @import("std").mem;
1const std = @import("std");
2const assert = std.debug.assert;
3const mem = std.mem;
4const builtin = @import("builtin");
35
46pub fn foo() error!i32 {
57 const x = try bar();
......@@ -74,3 +76,35 @@ fn doErrReturnInAssignment() error!void {
7476fn makeANonErr() error!i32 {
7577 return 1;
7678}
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 {
1515 \\use @import("std").io;
1616 \\use @import("foo.zig");
1717 \\
18 \\pub fn main() !void {
18 \\pub fn main() void {
1919 \\ privateFunction();
2020 \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);
2121 \\ stdout.print("OK 2\n") catch unreachable;
......@@ -49,7 +49,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
4949 \\use @import("foo.zig");
5050 \\use @import("bar.zig");
5151 \\
52 \\pub fn main() !void {
52 \\pub fn main() void {
5353 \\ foo_function();
5454 \\ bar_function();
5555 \\}
......@@ -89,7 +89,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
8989 var tc = cases.create("two files use import each other",
9090 \\use @import("a.zig");
9191 \\
92 \\pub fn main() !void {
92 \\pub fn main() void {
9393 \\ ok();
9494 \\}
9595 , "OK\n");
......@@ -118,7 +118,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
118118 cases.add("hello world without libc",
119119 \\const io = @import("std").io;
120120 \\
121 \\pub fn main() !void {
121 \\pub fn main() void {
122122 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
123123 \\ stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;
124124 \\}
......@@ -268,7 +268,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
268268 \\const z = io.stdin_fileno;
269269 \\const x : @typeOf(y) = 1234;
270270 \\const y : u16 = 5678;
271 \\pub fn main() !void {
271 \\pub fn main() void {
272272 \\ var x_local : i32 = print_ok(x);
273273 \\}
274274 \\fn print_ok(val: @typeOf(x)) @typeOf(foo) {
......@@ -351,7 +351,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
351351 \\ fn method(b: &const Bar) bool { return true; }
352352 \\};
353353 \\
354 \\pub fn main() !void {
354 \\pub fn main() void {
355355 \\ const bar = Bar {.field2 = 13,};
356356 \\ const foo = Foo {.field1 = bar,};
357357 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
......@@ -367,7 +367,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
367367
368368 cases.add("defer with only fallthrough",
369369 \\const io = @import("std").io;
370 \\pub fn main() !void {
370 \\pub fn main() void {
371371 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
372372 \\ stdout.print("before\n") catch unreachable;
373373 \\ defer stdout.print("defer1\n") catch unreachable;
......@@ -380,7 +380,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
380380 cases.add("defer with return",
381381 \\const io = @import("std").io;
382382 \\const os = @import("std").os;
383 \\pub fn main() !void {
383 \\pub fn main() void {
384384 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
385385 \\ stdout.print("before\n") catch unreachable;
386386 \\ defer stdout.print("defer1\n") catch unreachable;
......@@ -394,7 +394,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
394394
395395 cases.add("errdefer and it fails",
396396 \\const io = @import("std").io;
397 \\pub fn main() !void {
397 \\pub fn main() void {
398398 \\ do_test() catch return;
399399 \\}
400400 \\fn do_test() !void {
......@@ -406,7 +406,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
406406 \\ defer stdout.print("defer3\n") catch unreachable;
407407 \\ stdout.print("after\n") catch unreachable;
408408 \\}
409 \\error IToldYouItWouldFail;
410409 \\fn its_gonna_fail() !void {
411410 \\ return error.IToldYouItWouldFail;
412411 \\}
......@@ -414,7 +413,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
414413
415414 cases.add("errdefer and it passes",
416415 \\const io = @import("std").io;
417 \\pub fn main() !void {
416 \\pub fn main() void {
418417 \\ do_test() catch return;
419418 \\}
420419 \\fn do_test() !void {
......@@ -426,7 +425,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
426425 \\ defer stdout.print("defer3\n") catch unreachable;
427426 \\ stdout.print("after\n") catch unreachable;
428427 \\}
429 \\fn its_gonna_pass() %void { }
428 \\fn its_gonna_pass() error!void { }
430429 , "before\nafter\ndefer3\ndefer1\n");
431430
432431 cases.addCase(x: {
......@@ -434,7 +433,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
434433 \\const foo_txt = @embedFile("foo.txt");
435434 \\const io = @import("std").io;
436435 \\
437 \\pub fn main() !void {
436 \\pub fn main() void {
438437 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
439438 \\ stdout.print(foo_txt) catch unreachable;
440439 \\}
test/compile_errors.zig+33-15
......@@ -1,6 +1,25 @@
11const tests = @import("tests.zig");
22
33pub 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
423 cases.add("duplicate struct field",
524 \\const Foo = struct {
625 \\ Bar: i32,
......@@ -99,12 +118,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
99118
100119 cases.add("wrong return type for main",
101120 \\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
104123 cases.add("double ?? on main return value",
105124 \\pub fn main() ??void {
106125 \\}
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
109128 cases.add("bad identifier in function with struct defined inside function which references local const",
110129 \\export fn entry() void {
......@@ -1160,7 +1179,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
11601179 \\export fn f() void {
11611180 \\ try something();
11621181 \\}
1163 \\fn something() %void { }
1182 \\fn something() error!void { }
11641183 ,
11651184 ".tmp_source.zig:2:5: error: expected type 'void', found 'error'");
11661185
......@@ -1251,7 +1270,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
12511270 , ".tmp_source.zig:3:11: error: cannot assign to constant");
12521271
12531272 cases.add("main function with bogus args type",
1254 \\pub fn main(args: [][]bogus) %void {}
1273 \\pub fn main(args: [][]bogus) !void {}
12551274 , ".tmp_source.zig:1:23: error: use of undeclared identifier 'bogus'");
12561275
12571276 cases.add("for loop missing element param",
......@@ -1391,7 +1410,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
13911410 \\ const a = maybeInt() ?? return;
13921411 \\}
13931412 \\
1394 \\fn canFail() %void { }
1413 \\fn canFail() error!void { }
13951414 \\
13961415 \\pub fn maybeInt() ?i32 {
13971416 \\ return 0;
......@@ -1521,7 +1540,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
15211540 \\export fn foo() void {
15221541 \\ bar() catch unreachable;
15231542 \\}
1524 \\fn bar() %i32 { return 0; }
1543 \\fn bar() error!i32 { return 0; }
15251544 , ".tmp_source.zig:2:11: error: expression value is ignored");
15261545
15271546 cases.add("ignored statement value",
......@@ -1552,7 +1571,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
15521571 \\export fn foo() void {
15531572 \\ defer bar();
15541573 \\}
1555 \\fn bar() %i32 { return 0; }
1574 \\fn bar() error!i32 { return 0; }
15561575 , ".tmp_source.zig:2:14: error: expression value is ignored");
15571576
15581577 cases.add("dereference an array",
......@@ -1619,13 +1638,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
16191638 , ".tmp_source.zig:2:21: error: expected pointer, found 'usize'");
16201639
16211640 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;
1623 \\const u2 = @IntType(false, 2);
1624 \\fn foo(e: error) u2 {
1641 \\const Error = error { A, B, C, D, E, F, G, H };
1642 \\fn foo(e: Error) u2 {
16251643 \\ return u2(e);
16261644 \\}
16271645 \\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
16301648 cases.add("asm at compile time",
16311649 \\comptime {
......@@ -1808,9 +1826,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
18081826 \\export fn foo() void {
18091827 \\ while (bar()) {}
18101828 \\}
1811 \\fn bar() %i32 { return 1; }
1829 \\fn bar() error!i32 { return 1; }
18121830 ,
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
18151833 cases.add("while expected nullable, got bool",
18161834 \\export fn foo() void {
......@@ -1824,9 +1842,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
18241842 \\export fn foo() void {
18251843 \\ while (bar()) |x| {}
18261844 \\}
1827 \\fn bar() %i32 { return 1; }
1845 \\fn bar() error!i32 { return 1; }
18281846 ,
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
18311849 cases.add("while expected error union, got bool",
18321850 \\export fn foo() void {
test/standalone/brace_expansion/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) !void {
3pub fn build(b: &Builder) void {
44 const main = b.addTest("main.zig");
55 main.setBuildMode(b.standardReleaseOptions());
66
test/standalone/brace_expansion/main.zig+11-2
......@@ -68,7 +68,12 @@ const Node = union(enum) {
6868 Combine: []Node,
6969};
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 {
7277 const first_token = tokens.items[*token_index];
7378 *token_index += 1;
7479
......@@ -132,7 +137,11 @@ fn expandString(input: []const u8, output: &Buffer) !void {
132137 }
133138}
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 {
136145 assert(output.len == 0);
137146 switch (*node) {
138147 Node.Scalar => |scalar| {
test/standalone/issue_339/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) !void {
3pub fn build(b: &Builder) void {
44 const obj = b.addObject("test", "test.zig");
55
66 const test_step = b.step("test", "Test the program");
test/standalone/issue_339/test.zig+1-1
......@@ -1,7 +1,7 @@
11const StackTrace = @import("builtin").StackTrace;
22pub fn panic(msg: []const u8, stack_trace: ?&StackTrace) noreturn { @breakpoint(); while (true) {} }
33
4fn bar() %void {}
4fn bar() error!void {}
55
66export fn foo() void {
77 bar() catch unreachable;
test/standalone/pkg_import/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) !void {
3pub fn build(b: &Builder) void {
44 const exe = b.addExecutable("test", "test.zig");
55 exe.addPackagePath("my_pkg", "pkg.zig");
66
test/standalone/pkg_import/test.zig+1-1
......@@ -1,6 +1,6 @@
11const my_pkg = @import("my_pkg");
22const assert = @import("std").debug.assert;
33
4pub fn main() !void {
4pub fn main() void {
55 assert(my_pkg.add(10, 20) == 30);
66}
test/standalone/use_alias/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) !void {
3pub fn build(b: &Builder) void {
44 b.addCIncludePath(".");
55
66 const main = b.addTest("main.zig");