authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-09 00:47:57-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2018-02-09 00:47:57-05:00
log59119628425566691a6c580a3da378798bc6c648
tree7eeeaf4620f40e5a6203c9de91edbdab5e733a51
parent1c236b0766bbc68f1b04e32a95683e273b26714c
parent8e554561df7823e2aba0076f2fc98278df6cb8f2
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #759 from zig-lang/error-sets

Error Sets

83 files changed, 3263 insertions(+), 1607 deletions(-)

build.zig+2-2
...@@ -10,7 +10,7 @@ const ArrayList = std.ArrayList;...@@ -10,7 +10,7 @@ const ArrayList = std.ArrayList;
10const Buffer = std.Buffer;10const Buffer = std.Buffer;
11const io = std.io;11const io = std.io;
1212
13pub fn build(b: &Builder) %void {13pub fn build(b: &Builder) !void {
14 const mode = b.standardReleaseOptions();14 const mode = b.standardReleaseOptions();
1515
16 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");16 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
...@@ -149,7 +149,7 @@ const LibraryDep = struct {...@@ -149,7 +149,7 @@ const LibraryDep = struct {
149 includes: ArrayList([]const u8),149 includes: ArrayList([]const u8),
150};150};
151151
152fn findLLVM(b: &Builder, llvm_config_exe: []const u8) %LibraryDep {152fn findLLVM(b: &Builder, llvm_config_exe: []const u8) !LibraryDep {
153 const libs_output = try b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});153 const libs_output = try b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});
154 const includes_output = try b.exec([][]const u8{llvm_config_exe, "--includedir"});154 const includes_output = try b.exec([][]const u8{llvm_config_exe, "--includedir"});
155 const libdir_output = try b.exec([][]const u8{llvm_config_exe, "--libdir"});155 const libdir_output = try b.exec([][]const u8{llvm_config_exe, "--libdir"});
ci/appveyor/build_script.bat+3-4
...@@ -30,11 +30,10 @@ cd %APPVEYOR_BUILD_FOLDER%...@@ -30,11 +30,10 @@ cd %APPVEYOR_BUILD_FOLDER%
30SET "PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%"30SET "PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%"
31SET "MSYSTEM=MINGW64"31SET "MSYSTEM=MINGW64"
3232
33bash -lc "pacman -Syu --needed --noconfirm"33bash -lc "yes | pacman -Syu --needed --noconfirm"
34bash -lc "pacman -Su --needed --noconfirm"34bash -lc "yes | pacman -Su --needed --noconfirm"
3535
36bash -lc "pacman -S --needed --noconfirm make mingw64/mingw-w64-x86_64-make mingw64/mingw-w64-x86_64-cmake mingw64/mingw-w64-x86_64-clang mingw64/mingw-w64-x86_64-llvm mingw64/mingw-w64-x86_64-lld mingw64/mingw-w64-x86_64-gcc"36bash -lc "yes | pacman -S --needed --noconfirm make mingw64/mingw-w64-x86_64-make mingw64/mingw-w64-x86_64-cmake mingw64/mingw-w64-x86_64-clang mingw64/mingw-w64-x86_64-llvm mingw64/mingw-w64-x86_64-lld mingw64/mingw-w64-x86_64-gcc"
3737
38bash -lc "cd ${APPVEYOR_BUILD_FOLDER} && mkdir build && cd build && cmake .. -G""MSYS Makefiles"" -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_LIB_DIR=$(dirname $(cc -print-file-name=crt1.o)) -DZIG_LIBC_INCLUDE_DIR=$(echo -n | cc -E -x c - -v 2>&1 | grep -B1 ""End of search list."" | head -n1 | cut -c 2- | sed ""s/ .*//"") -DZIG_LIBC_STATIC_LIB_DIR=$(dirname $(cc -print-file-name=crtbegin.o)) && make && make install"38bash -lc "cd ${APPVEYOR_BUILD_FOLDER} && mkdir build && cd build && cmake .. -G""MSYS Makefiles"" -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_LIB_DIR=$(dirname $(cc -print-file-name=crt1.o)) -DZIG_LIBC_INCLUDE_DIR=$(echo -n | cc -E -x c - -v 2>&1 | grep -B1 ""End of search list."" | head -n1 | cut -c 2- | sed ""s/ .*//"") -DZIG_LIBC_STATIC_LIB_DIR=$(dirname $(cc -print-file-name=crtbegin.o)) && make && make install"
3939
40@echo "MinGW build successful"
doc/docgen.zig+10-19
...@@ -12,7 +12,7 @@ const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt();...@@ -12,7 +12,7 @@ const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt();
12const obj_ext = std.build.Target(std.build.Target.Native).oFileExt();12const obj_ext = std.build.Target(std.build.Target.Native).oFileExt();
13const tmp_dir_name = "docgen_tmp";13const tmp_dir_name = "docgen_tmp";
1414
15pub fn main() %void {15pub fn main() !void {
16 // TODO use a more general purpose allocator here16 // TODO use a more general purpose allocator here
17 var inc_allocator = try std.heap.IncrementingAllocator.init(max_doc_file_size);17 var inc_allocator = try std.heap.IncrementingAllocator.init(max_doc_file_size);
18 defer inc_allocator.deinit();18 defer inc_allocator.deinit();
...@@ -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);
...@@ -243,13 +241,13 @@ fn parseError(tokenizer: &Tokenizer, token: &const Token, comptime fmt: []const...@@ -243,13 +241,13 @@ fn parseError(tokenizer: &Tokenizer, token: &const Token, comptime fmt: []const
243 return error.ParseError;241 return error.ParseError;
244}242}
245243
246fn assertToken(tokenizer: &Tokenizer, token: &const Token, id: Token.Id) %void {244fn assertToken(tokenizer: &Tokenizer, token: &const Token, id: Token.Id) !void {
247 if (token.id != id) {245 if (token.id != id) {
248 return parseError(tokenizer, token, "expected {}, found {}", @tagName(id), @tagName(token.id));246 return parseError(tokenizer, token, "expected {}, found {}", @tagName(id), @tagName(token.id));
249 }247 }
250}248}
251249
252fn eatToken(tokenizer: &Tokenizer, id: Token.Id) %Token {250fn eatToken(tokenizer: &Tokenizer, id: Token.Id) !Token {
253 const token = tokenizer.next();251 const token = tokenizer.next();
254 try assertToken(tokenizer, token, id);252 try assertToken(tokenizer, token, id);
255 return token;253 return token;
...@@ -316,7 +314,7 @@ const Action = enum {...@@ -316,7 +314,7 @@ const Action = enum {
316 Close,314 Close,
317};315};
318316
319fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) %Toc {317fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
320 var urls = std.HashMap([]const u8, Token, mem.hash_slice_u8, mem.eql_slice_u8).init(allocator);318 var urls = std.HashMap([]const u8, Token, mem.hash_slice_u8, mem.eql_slice_u8).init(allocator);
321 errdefer urls.deinit();319 errdefer urls.deinit();
322320
...@@ -540,7 +538,7 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) %Toc {...@@ -540,7 +538,7 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) %Toc {
540 };538 };
541}539}
542540
543fn urlize(allocator: &mem.Allocator, input: []const u8) %[]u8 {541fn urlize(allocator: &mem.Allocator, input: []const u8) ![]u8 {
544 var buf = try std.Buffer.initSize(allocator, 0);542 var buf = try std.Buffer.initSize(allocator, 0);
545 defer buf.deinit();543 defer buf.deinit();
546544
...@@ -560,7 +558,7 @@ fn urlize(allocator: &mem.Allocator, input: []const u8) %[]u8 {...@@ -560,7 +558,7 @@ fn urlize(allocator: &mem.Allocator, input: []const u8) %[]u8 {
560 return buf.toOwnedSlice();558 return buf.toOwnedSlice();
561}559}
562560
563fn escapeHtml(allocator: &mem.Allocator, input: []const u8) %[]u8 {561fn escapeHtml(allocator: &mem.Allocator, input: []const u8) ![]u8 {
564 var buf = try std.Buffer.initSize(allocator, 0);562 var buf = try std.Buffer.initSize(allocator, 0);
565 defer buf.deinit();563 defer buf.deinit();
566564
...@@ -596,15 +594,13 @@ const TermState = enum {...@@ -596,15 +594,13 @@ 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);
604 assert(mem.eql(u8, result, "A<span class=\"t32\">green</span>B"));600 assert(mem.eql(u8, result, "A<span class=\"t32\">green</span>B"));
605}601}
606602
607fn termColor(allocator: &mem.Allocator, input: []const u8) %[]u8 {603fn termColor(allocator: &mem.Allocator, input: []const u8) ![]u8 {
608 var buf = try std.Buffer.initSize(allocator, 0);604 var buf = try std.Buffer.initSize(allocator, 0);
609 defer buf.deinit();605 defer buf.deinit();
610606
...@@ -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,10 +968,7 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io...@@ -974,10 +968,7 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io
974968
975}969}
976970
977error ChildCrashed;971fn exec(allocator: &mem.Allocator, args: []const []const u8) !os.ChildProcess.ExecResult {
978error ChildExitError;
979
980fn 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) {
983 os.ChildProcess.Term.Exited => |exit_code| {974 os.ChildProcess.Term.Exited => |exit_code| {
doc/langref.html.in+62-76
...@@ -108,7 +108,7 @@...@@ -108,7 +108,7 @@
108 {#code_begin|exe|hello#}108 {#code_begin|exe|hello#}
109const std = @import("std");109const std = @import("std");
110110
111pub fn main() %void {111pub fn main() !void {
112 // If this program is run without stdout attached, exit with an error.112 // If this program is run without stdout attached, exit with an error.
113 var stdout_file = try std.io.getStdOut();113 var stdout_file = try std.io.getStdOut();
114 // If this program encounters pipe failure when printing to stdout, exit114 // If this program encounters pipe failure when printing to stdout, exit
...@@ -129,8 +129,8 @@ pub fn main() void {...@@ -129,8 +129,8 @@ pub fn main() void {
129}129}
130 {#code_end#}130 {#code_end#}
131 <p>131 <p>
132 Note that we also left off the <code class="zig">%</code> from the return type.132 Note that we also left off the <code class="zig">!</code> from the return type.
133 In Zig, if your main function cannot fail, you may use the <code class="zig">void</code> return type.133 In Zig, if your main function cannot fail, you must use the <code class="zig">void</code> return type.
134 </p>134 </p>
135 {#see_also|Values|@import|Errors|Root Source File#}135 {#see_also|Values|@import|Errors|Root Source File#}
136 {#header_close#}136 {#header_close#}
...@@ -141,10 +141,7 @@ const warn = std.debug.warn;...@@ -141,10 +141,7 @@ const warn = std.debug.warn;
141const os = std.os;141const os = std.os;
142const assert = std.debug.assert;142const assert = std.debug.assert;
143143
144// error declaration, makes `error.ArgNotFound` available144pub fn main() void {
145error ArgNotFound;
146
147pub fn main() %void {
148 // integers145 // integers
149 const one_plus_one: i32 = 1 + 1;146 const one_plus_one: i32 = 1 + 1;
150 warn("1 + 1 = {}\n", one_plus_one);147 warn("1 + 1 = {}\n", one_plus_one);
...@@ -173,7 +170,7 @@ pub fn main() %void {...@@ -173,7 +170,7 @@ pub fn main() %void {
173 @typeName(@typeOf(nullable_value)), nullable_value);170 @typeName(@typeOf(nullable_value)), nullable_value);
174171
175 // error union172 // error union
176 var number_or_error: %i32 = error.ArgNotFound;173 var number_or_error: error!i32 = error.ArgNotFound;
177174
178 warn("\nerror union 1\ntype: {}\nvalue: {}\n",175 warn("\nerror union 1\ntype: {}\nvalue: {}\n",
179 @typeName(@typeOf(number_or_error)), number_or_error);176 @typeName(@typeOf(number_or_error)), number_or_error);
...@@ -681,7 +678,7 @@ const warn = @import("std").debug.warn;...@@ -681,7 +678,7 @@ const warn = @import("std").debug.warn;
681extern fn foo_strict(x: f64) f64;678extern fn foo_strict(x: f64) f64;
682extern fn foo_optimized(x: f64) f64;679extern fn foo_optimized(x: f64) f64;
683680
684pub fn main() %void {681pub fn main() void {
685 const x = 0.001;682 const x = 0.001;
686 warn("optimized = {}\n", foo_optimized(x));683 warn("optimized = {}\n", foo_optimized(x));
687 warn("strict = {}\n", foo_strict(x));684 warn("strict = {}\n", foo_strict(x));
...@@ -1036,7 +1033,7 @@ a catch |err| b</code></pre></td>...@@ -1036,7 +1033,7 @@ a catch |err| b</code></pre></td>
1036 <code>err</code> is the <code>error</code> and is in scope of the expression <code>b</code>.1033 <code>err</code> is the <code>error</code> and is in scope of the expression <code>b</code>.
1037 </td>1034 </td>
1038 <td>1035 <td>
1039 <pre><code class="zig">const value: %u32 = null;1036 <pre><code class="zig">const value: error!u32 = error.Broken;
1040const unwrapped = value catch 1234;1037const unwrapped = value catch 1234;
1041unwrapped == 1234</code></pre>1038unwrapped == 1234</code></pre>
1042 </td>1039 </td>
...@@ -1269,9 +1266,10 @@ const ptr = &amp;x;...@@ -1269,9 +1266,10 @@ const ptr = &amp;x;
1269 {#header_close#}1266 {#header_close#}
1270 {#header_open|Precedence#}1267 {#header_open|Precedence#}
1271 <pre><code>x() x[] x.y1268 <pre><code>x() x[] x.y
1272!x -x -%x ~x *x &amp;x ?x %x ??x1269a!b
1270!x -x -%x ~x *x &amp;x ?x ??x
1273x{}1271x{}
1274* / % ** *%1272! * / % ** *%
1275+ - ++ +% -%1273+ - ++ +% -%
1276&lt;&lt; &gt;&gt;1274&lt;&lt; &gt;&gt;
1277&amp;1275&amp;
...@@ -2268,8 +2266,8 @@ fn eventuallyNullSequence() ?u32 {...@@ -2268,8 +2266,8 @@ fn eventuallyNullSequence() ?u32 {
2268 break :blk numbers_left;2266 break :blk numbers_left;
2269 };2267 };
2270}2268}
2271error ReachedZero;2269
2272fn eventuallyErrorSequence() %u32 {2270fn eventuallyErrorSequence() error!u32 {
2273 return if (numbers_left == 0) error.ReachedZero else blk: {2271 return if (numbers_left == 0) error.ReachedZero else blk: {
2274 numbers_left -= 1;2272 numbers_left -= 1;
2275 break :blk numbers_left;2273 break :blk numbers_left;
...@@ -2398,7 +2396,7 @@ fn typeNameLength(comptime T: type) usize {...@@ -2398,7 +2396,7 @@ fn typeNameLength(comptime T: type) usize {
2398// If expressions have three uses, corresponding to the three types:2396// If expressions have three uses, corresponding to the three types:
2399// * bool2397// * bool
2400// * ?T2398// * ?T
2401// * %T2399// * error!T
24022400
2403const assert = @import("std").debug.assert;2401const assert = @import("std").debug.assert;
24042402
...@@ -2459,20 +2457,18 @@ test "if nullable" {...@@ -2459,20 +2457,18 @@ test "if nullable" {
2459 }2457 }
2460}2458}
24612459
2462error BadValue;
2463error LessBadValue;
2464test "if error union" {2460test "if error union" {
2465 // If expressions test for errors.2461 // If expressions test for errors.
2466 // Note the |err| capture on the else.2462 // Note the |err| capture on the else.
24672463
2468 const a: %u32 = 0;2464 const a: error!u32 = 0;
2469 if (a) |value| {2465 if (a) |value| {
2470 assert(value == 0);2466 assert(value == 0);
2471 } else |err| {2467 } else |err| {
2472 unreachable;2468 unreachable;
2473 }2469 }
24742470
2475 const b: %u32 = error.BadValue;2471 const b: error!u32 = error.BadValue;
2476 if (b) |value| {2472 if (b) |value| {
2477 unreachable;2473 unreachable;
2478 } else |err| {2474 } else |err| {
...@@ -2490,7 +2486,7 @@ test "if error union" {...@@ -2490,7 +2486,7 @@ test "if error union" {
2490 }2486 }
24912487
2492 // Access the value by reference using a pointer capture.2488 // Access the value by reference using a pointer capture.
2493 var c: %u32 = 3;2489 var c: error!u32 = 3;
2494 if (c) |*value| {2490 if (c) |*value| {
2495 *value = 9;2491 *value = 9;
2496 } else |err| {2492 } else |err| {
...@@ -2558,8 +2554,7 @@ test "defer unwinding" {...@@ -2558,8 +2554,7 @@ test "defer unwinding" {
2558//2554//
2559// This is especially useful in allowing a function to clean up properly2555// This is especially useful in allowing a function to clean up properly
2560// on error, and replaces goto error handling tactics as seen in c.2556// on error, and replaces goto error handling tactics as seen in c.
2561error DeferError;2557fn deferErrorExample(is_error: bool) !void {
2562fn deferErrorExample(is_error: bool) %void {
2563 warn("\nstart of function\n");2558 warn("\nstart of function\n");
25642559
2565 // This will always be executed on exit2560 // This will always be executed on exit
...@@ -2668,7 +2663,7 @@ test "foo" {...@@ -2668,7 +2663,7 @@ test "foo" {
2668 assert(value == 1234);2663 assert(value == 1234);
2669}2664}
26702665
2671fn bar() %u32 {2666fn bar() error!u32 {
2672 return 1234;2667 return 1234;
2673}2668}
26742669
...@@ -2791,13 +2786,8 @@ test "fn reflection" {...@@ -2791,13 +2786,8 @@ test "fn reflection" {
2791 One of the distinguishing features of Zig is its exception handling strategy.2786 One of the distinguishing features of Zig is its exception handling strategy.
2792 </p>2787 </p>
2793 <p>2788 <p>
2794 Among the top level declarations available is the error value declaration:2789 TODO rewrite the errors section to take into account error sets
2795 </p>2790 </p>
2796 {#code_begin|syntax#}
2797error FileNotFound;
2798error OutOfMemory;
2799error UnexpectedToken;
2800 {#code_end#}
2801 <p>2791 <p>
2802 These error values are assigned an unsigned integer value greater than 0 at2792 These error values are assigned an unsigned integer value greater than 0 at
2803 compile time. You are allowed to declare the same error value more than once,2793 compile time. You are allowed to declare the same error value more than once,
...@@ -2809,26 +2799,23 @@ error UnexpectedToken;...@@ -2809,26 +2799,23 @@ error UnexpectedToken;
2809 </p>2799 </p>
2810 <p>2800 <p>
2811 Each error value across the entire compilation unit gets a unique integer,2801 Each error value across the entire compilation unit gets a unique integer,
2812 and this determines the size of the pure error type.2802 and this determines the size of the error set type.
2813 </p>2803 </p>
2814 <p>2804 <p>
2815 The pure error type is one of the error values, and in the same way that pointers2805 The error set type is one of the error values, and in the same way that pointers
2816 cannot be null, a pure error is always an error.2806 cannot be null, a error set instance is always an error.
2817 </p>2807 </p>
2818 {#code_begin|syntax#}const pure_error = error.FileNotFound;{#code_end#}2808 {#code_begin|syntax#}const pure_error = error.FileNotFound;{#code_end#}
2819 <p>2809 <p>
2820 Most of the time you will not find yourself using a pure error type. Instead,2810 Most of the time you will not find yourself using an error set type. Instead,
2821 likely you will be using the error union type. This is when you take a normal type,2811 likely you will be using the error union type. This is when you take an error set
2822 and prefix it with the <code>%</code> operator.2812 and a normal type, and create an error union with the <code>!</code> binary operator.
2823 </p>2813 </p>
2824 <p>2814 <p>
2825 Here is a function to parse a string into a 64-bit integer:2815 Here is a function to parse a string into a 64-bit integer:
2826 </p>2816 </p>
2827 {#code_begin|test#}2817 {#code_begin|test#}
2828error InvalidChar;2818pub fn parseU64(buf: []const u8, radix: u8) !u64 {
2829error Overflow;
2830
2831pub fn parseU64(buf: []const u8, radix: u8) %u64 {
2832 var x: u64 = 0;2819 var x: u64 = 0;
28332820
2834 for (buf) |c| {2821 for (buf) |c| {
...@@ -2867,13 +2854,14 @@ test "parse u64" {...@@ -2867,13 +2854,14 @@ test "parse u64" {
2867}2854}
2868 {#code_end#}2855 {#code_end#}
2869 <p>2856 <p>
2870 Notice the return type is <code>%u64</code>. This means that the function2857 Notice the return type is <code>!u64</code>. This means that the function
2871 either returns an unsigned 64 bit integer, or an error.2858 either returns an unsigned 64 bit integer, or an error. We left off the error set
2859 to the left of the <code>!</code>, so the error set is inferred.
2872 </p>2860 </p>
2873 <p>2861 <p>
2874 Within the function definition, you can see some return statements that return2862 Within the function definition, you can see some return statements that return
2875 a pure error, and at the bottom a return statement that returns a <code>u64</code>.2863 an error, and at the bottom a return statement that returns a <code>u64</code>.
2876 Both types implicitly cast to <code>%u64</code>.2864 Both types implicitly cast to <code>error!u64</code>.
2877 </p>2865 </p>
2878 <p>2866 <p>
2879 What it looks like to use this function varies depending on what you're2867 What it looks like to use this function varies depending on what you're
...@@ -2900,7 +2888,7 @@ fn doAThing(str: []u8) void {...@@ -2900,7 +2888,7 @@ fn doAThing(str: []u8) void {
2900 <p>Let's say you wanted to return the error if you got one, otherwise continue with the2888 <p>Let's say you wanted to return the error if you got one, otherwise continue with the
2901 function logic:</p>2889 function logic:</p>
2902 {#code_begin|syntax#}2890 {#code_begin|syntax#}
2903fn doAThing(str: []u8) %void {2891fn doAThing(str: []u8) !void {
2904 const number = parseU64(str, 10) catch |err| return err;2892 const number = parseU64(str, 10) catch |err| return err;
2905 // ...2893 // ...
2906}2894}
...@@ -2909,7 +2897,7 @@ fn doAThing(str: []u8) %void {...@@ -2909,7 +2897,7 @@ fn doAThing(str: []u8) %void {
2909 There is a shortcut for this. The <code>try</code> expression:2897 There is a shortcut for this. The <code>try</code> expression:
2910 </p>2898 </p>
2911 {#code_begin|syntax#}2899 {#code_begin|syntax#}
2912fn doAThing(str: []u8) %void {2900fn doAThing(str: []u8) !void {
2913 const number = try parseU64(str, 10);2901 const number = try parseU64(str, 10);
2914 // ...2902 // ...
2915}2903}
...@@ -2959,7 +2947,7 @@ fn doAThing(str: []u8) void {...@@ -2959,7 +2947,7 @@ fn doAThing(str: []u8) void {
2959 Example:2947 Example:
2960 </p>2948 </p>
2961 {#code_begin|syntax#}2949 {#code_begin|syntax#}
2962fn createFoo(param: i32) %Foo {2950fn createFoo(param: i32) !Foo {
2963 const foo = try tryToAllocateFoo();2951 const foo = try tryToAllocateFoo();
2964 // now we have allocated foo. we need to free it if the function fails.2952 // now we have allocated foo. we need to free it if the function fails.
2965 // but we want to return it if the function succeeds.2953 // but we want to return it if the function succeeds.
...@@ -2999,15 +2987,13 @@ fn createFoo(param: i32) %Foo {...@@ -2999,15 +2987,13 @@ fn createFoo(param: i32) %Foo {
2999 </ul>2987 </ul>
3000 {#see_also|defer|if|switch#}2988 {#see_also|defer|if|switch#}
3001 {#header_open|Error Union Type#}2989 {#header_open|Error Union Type#}
3002 <p>An error union is created by putting a <code>%</code> in front of a type.2990 <p>An error union is created with the <code>!</code> binary operator.
3003 You can use compile-time reflection to access the child type of an error union:</p>2991 You can use compile-time reflection to access the child type of an error union:</p>
3004 {#code_begin|test#}2992 {#code_begin|test#}
3005const assert = @import("std").debug.assert;2993const assert = @import("std").debug.assert;
30062994
3007error SomeError;
3008
3009test "error union" {2995test "error union" {
3010 var foo: %i32 = undefined;2996 var foo: error!i32 = undefined;
30112997
3012 // Implicitly cast from child type of an error union:2998 // Implicitly cast from child type of an error union:
3013 foo = 1234;2999 foo = 1234;
...@@ -3015,8 +3001,11 @@ test "error union" {...@@ -3015,8 +3001,11 @@ test "error union" {
3015 // Implicitly cast from an error set:3001 // Implicitly cast from an error set:
3016 foo = error.SomeError;3002 foo = error.SomeError;
30173003
3018 // Use compile-time reflection to access the child type of an error union:3004 // Use compile-time reflection to access the payload type of an error union:
3019 comptime assert(@typeOf(foo).Child == i32);3005 comptime assert(@typeOf(foo).Payload == i32);
3006
3007 // Use compile-time reflection to access the error set type of an error union:
3008 comptime assert(@typeOf(foo).ErrorSet == error);
3020}3009}
3021 {#code_end#}3010 {#code_end#}
3022 {#header_close#}3011 {#header_close#}
...@@ -3610,7 +3599,7 @@ pub fn main() void {...@@ -3610,7 +3599,7 @@ pub fn main() void {
36103599
3611 {#code_begin|syntax#}3600 {#code_begin|syntax#}
3612/// Calls print and then flushes the buffer.3601/// Calls print and then flushes the buffer.
3613pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) %void {3602pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) error!void {
3614 const State = enum {3603 const State = enum {
3615 Start,3604 Start,
3616 OpenBrace,3605 OpenBrace,
...@@ -3682,7 +3671,7 @@ pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) %void {...@@ -3682,7 +3671,7 @@ pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) %void {
3682 and emits a function that actually looks like this:3671 and emits a function that actually looks like this:
3683 </p>3672 </p>
3684 {#code_begin|syntax#}3673 {#code_begin|syntax#}
3685pub fn printf(self: &OutStream, arg0: i32, arg1: []const u8) %void {3674pub fn printf(self: &OutStream, arg0: i32, arg1: []const u8) !void {
3686 try self.write("here is a string: '");3675 try self.write("here is a string: '");
3687 try self.printValue(arg0);3676 try self.printValue(arg0);
3688 try self.write("' here is a number: ");3677 try self.write("' here is a number: ");
...@@ -3696,7 +3685,7 @@ pub fn printf(self: &OutStream, arg0: i32, arg1: []const u8) %void {...@@ -3696,7 +3685,7 @@ pub fn printf(self: &OutStream, arg0: i32, arg1: []const u8) %void {
3696 on the type:3685 on the type:
3697 </p>3686 </p>
3698 {#code_begin|syntax#}3687 {#code_begin|syntax#}
3699pub fn printValue(self: &OutStream, value: var) %void {3688pub fn printValue(self: &OutStream, value: var) !void {
3700 const T = @typeOf(value);3689 const T = @typeOf(value);
3701 if (@isInteger(T)) {3690 if (@isInteger(T)) {
3702 return self.printInt(T, value);3691 return self.printInt(T, value);
...@@ -4647,7 +4636,7 @@ pub const TypeId = enum {...@@ -4647,7 +4636,7 @@ pub const TypeId = enum {
4647 {#code_begin|syntax#}4636 {#code_begin|syntax#}
4648const Builder = @import("std").build.Builder;4637const Builder = @import("std").build.Builder;
46494638
4650pub fn build(b: &Builder) %void {4639pub fn build(b: &Builder) void {
4651 const exe = b.addExecutable("example", "example.zig");4640 const exe = b.addExecutable("example", "example.zig");
4652 exe.setBuildMode(b.standardReleaseOptions());4641 exe.setBuildMode(b.standardReleaseOptions());
4653 b.default_step.dependOn(&exe.step);4642 b.default_step.dependOn(&exe.step);
...@@ -4789,7 +4778,7 @@ comptime {...@@ -4789,7 +4778,7 @@ comptime {
4789 {#code_begin|exe_err#}4778 {#code_begin|exe_err#}
4790const math = @import("std").math;4779const math = @import("std").math;
4791const warn = @import("std").debug.warn;4780const warn = @import("std").debug.warn;
4792pub fn main() %void {4781pub fn main() !void {
4793 var byte: u8 = 255;4782 var byte: u8 = 255;
47944783
4795 byte = if (math.add(u8, byte, 1)) |result| result else |err| {4784 byte = if (math.add(u8, byte, 1)) |result| result else |err| {
...@@ -4817,7 +4806,7 @@ pub fn main() %void {...@@ -4817,7 +4806,7 @@ pub fn main() %void {
4817 </p>4806 </p>
4818 {#code_begin|exe#}4807 {#code_begin|exe#}
4819const warn = @import("std").debug.warn;4808const warn = @import("std").debug.warn;
4820pub fn main() %void {4809pub fn main() void {
4821 var byte: u8 = 255;4810 var byte: u8 = 255;
48224811
4823 var result: u8 = undefined;4812 var result: u8 = undefined;
...@@ -4926,14 +4915,12 @@ pub fn main() void {...@@ -4926,14 +4915,12 @@ pub fn main() void {
4926 {#header_close#}4915 {#header_close#}
4927 {#header_open|Attempt to Unwrap Error#}4916 {#header_open|Attempt to Unwrap Error#}
4928 <p>At compile-time:</p>4917 <p>At compile-time:</p>
4929 {#code_begin|test_err|unable to unwrap error 'UnableToReturnNumber'#}4918 {#code_begin|test_err|caught unexpected error 'UnableToReturnNumber'#}
4930comptime {4919comptime {
4931 const number = getNumberOrFail() catch unreachable;4920 const number = getNumberOrFail() catch unreachable;
4932}4921}
49334922
4934error UnableToReturnNumber;4923fn getNumberOrFail() !i32 {
4935
4936fn getNumberOrFail() %i32 {
4937 return error.UnableToReturnNumber;4924 return error.UnableToReturnNumber;
4938}4925}
4939 {#code_end#}4926 {#code_end#}
...@@ -4953,9 +4940,7 @@ pub fn main() void {...@@ -4953,9 +4940,7 @@ pub fn main() void {
4953 }4940 }
4954}4941}
49554942
4956error UnableToReturnNumber;4943fn getNumberOrFail() !i32 {
4957
4958fn getNumberOrFail() %i32 {
4959 return error.UnableToReturnNumber;4944 return error.UnableToReturnNumber;
4960}4945}
4961 {#code_end#}4946 {#code_end#}
...@@ -4963,7 +4948,6 @@ fn getNumberOrFail() %i32 {...@@ -4963,7 +4948,6 @@ fn getNumberOrFail() %i32 {
4963 {#header_open|Invalid Error Code#}4948 {#header_open|Invalid Error Code#}
4964 <p>At compile-time:</p>4949 <p>At compile-time:</p>
4965 {#code_begin|test_err|integer value 11 represents no error#}4950 {#code_begin|test_err|integer value 11 represents no error#}
4966error AnError;
4967comptime {4951comptime {
4968 const err = error.AnError;4952 const err = error.AnError;
4969 const number = u32(err) + 10;4953 const number = u32(err) + 10;
...@@ -5363,7 +5347,7 @@ int main(int argc, char **argv) {...@@ -5363,7 +5347,7 @@ int main(int argc, char **argv) {
5363 {#code_begin|syntax#}5347 {#code_begin|syntax#}
5364const Builder = @import("std").build.Builder;5348const Builder = @import("std").build.Builder;
53655349
5366pub fn build(b: &Builder) %void {5350pub fn build(b: &Builder) void {
5367 const obj = b.addObject("base64", "base64.zig");5351 const obj = b.addObject("base64", "base64.zig");
53685352
5369 const exe = b.addCExecutable("test");5353 const exe = b.addCExecutable("test");
...@@ -5641,14 +5625,12 @@ fn readU32Be() u32 {}...@@ -5641,14 +5625,12 @@ fn readU32Be() u32 {}
5641 {#header_open|Grammar#}5625 {#header_open|Grammar#}
5642 <pre><code class="nohighlight">Root = many(TopLevelItem) EOF5626 <pre><code class="nohighlight">Root = many(TopLevelItem) EOF
56435627
5644TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestDecl5628TopLevelItem = CompTimeExpression(Block) | TopLevelDecl | TestDecl
56455629
5646TestDecl = "test" String Block5630TestDecl = "test" String Block
56475631
5648TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl)5632TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl)
56495633
5650ErrorValueDecl = "error" Symbol ";"
5651
5652GlobalVarDecl = option("export") VariableDeclaration ";"5634GlobalVarDecl = option("export") VariableDeclaration ";"
56535635
5654LocalVarDecl = option("comptime") VariableDeclaration5636LocalVarDecl = option("comptime") VariableDeclaration
...@@ -5663,7 +5645,7 @@ UseDecl = "use" Expression ";"...@@ -5663,7 +5645,7 @@ UseDecl = "use" Expression ";"
56635645
5664ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"5646ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"
56655647
5666FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") TypeExpr5648FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
56675649
5668FnDef = option("inline" | "export") FnProto Block5650FnDef = option("inline" | "export") FnProto Block
56695651
...@@ -5675,7 +5657,9 @@ Block = option(Symbol ":") "{" many(Statement) "}"...@@ -5675,7 +5657,9 @@ Block = option(Symbol ":") "{" many(Statement) "}"
56755657
5676Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"5658Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
56775659
5678TypeExpr = PrefixOpExpression | "var"5660TypeExpr = ErrorSetExpr | "var"
5661
5662ErrorSetExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression
56795663
5680BlockOrExpression = Block | Expression5664BlockOrExpression = Block | Expression
56815665
...@@ -5757,9 +5741,9 @@ MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression |...@@ -5757,9 +5741,9 @@ MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression |
57575741
5758CurlySuffixExpression = TypeExpr option(ContainerInitExpression)5742CurlySuffixExpression = TypeExpr option(ContainerInitExpression)
57595743
5760MultiplyOperator = "*" | "/" | "%" | "**" | "*%"5744MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
57615745
5762PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression5746PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression
57635747
5764SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)5748SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
57655749
...@@ -5777,9 +5761,9 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",")...@@ -5777,9 +5761,9 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",")
57775761
5778StructLiteralField = "." Symbol "=" Expression5762StructLiteralField = "." Symbol "=" Expression
57795763
5780PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "%" | "??" | "-%" | "try"5764PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try"
57815765
5782PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl | ("continue" option(":" Symbol))5766PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl
57835767
5784ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr5768ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr
57855769
...@@ -5787,6 +5771,8 @@ GroupedExpression = "(" Expression ")"...@@ -5787,6 +5771,8 @@ GroupedExpression = "(" Expression ")"
57875771
5788KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable"5772KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable"
57895773
5774ErrorSetDecl = "error" "{" list(Symbol, ",") "}"
5775
5790ContainerDecl = option("extern" | "packed")5776ContainerDecl = option("extern" | "packed")
5791 ("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression)))5777 ("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression)))
5792 "{" many(ContainerMember) "}"</code></pre>5778 "{" many(ContainerMember) "}"</code></pre>
example/cat/main.zig+4-4
...@@ -5,7 +5,7 @@ const os = std.os;...@@ -5,7 +5,7 @@ const os = std.os;
5const warn = std.debug.warn;5const warn = std.debug.warn;
6const allocator = std.debug.global_allocator;6const allocator = std.debug.global_allocator;
77
8pub fn main() %void {8pub fn main() !void {
9 var args_it = os.args();9 var args_it = os.args();
10 const exe = try unwrapArg(??args_it.next(allocator));10 const exe = try unwrapArg(??args_it.next(allocator));
11 var catted_anything = false;11 var catted_anything = false;
...@@ -36,12 +36,12 @@ pub fn main() %void {...@@ -36,12 +36,12 @@ pub fn main() %void {
36 }36 }
37}37}
3838
39fn usage(exe: []const u8) %void {39fn usage(exe: []const u8) !void {
40 warn("Usage: {} [FILE]...\n", exe);40 warn("Usage: {} [FILE]...\n", exe);
41 return error.Invalid;41 return error.Invalid;
42}42}
4343
44fn cat_file(stdout: &io.File, file: &io.File) %void {44fn cat_file(stdout: &io.File, file: &io.File) !void {
45 var buf: [1024 * 4]u8 = undefined;45 var buf: [1024 * 4]u8 = undefined;
4646
47 while (true) {47 while (true) {
...@@ -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/guess_number/main.zig+1-1
...@@ -5,7 +5,7 @@ const fmt = std.fmt;...@@ -5,7 +5,7 @@ const fmt = std.fmt;
5const Rand = std.rand.Rand;5const Rand = std.rand.Rand;
6const os = std.os;6const os = std.os;
77
8pub fn main() %void {8pub fn main() !void {
9 var stdout_file = try io.getStdOut();9 var stdout_file = try io.getStdOut();
10 var stdout_file_stream = io.FileOutStream.init(&stdout_file);10 var stdout_file_stream = io.FileOutStream.init(&stdout_file);
11 const stdout = &stdout_file_stream.stream;11 const stdout = &stdout_file_stream.stream;
example/hello_world/hello.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn main() %void {3pub fn main() !void {
4 // If this program is run without stdout attached, exit with an error.4 // If this program is run without stdout attached, exit with an error.
5 var stdout_file = try std.io.getStdOut();5 var stdout_file = try std.io.getStdOut();
6 // If this program encounters pipe failure when printing to stdout, exit6 // If this program encounters pipe failure when printing to stdout, exit
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+7-11
...@@ -14,13 +14,9 @@ const builtin = @import("builtin");...@@ -14,13 +14,9 @@ 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 {
24 main2() catch |err| {20 main2() catch |err| {
25 if (err != error.InvalidCommandLineArguments) {21 if (err != error.InvalidCommandLineArguments) {
26 warn("{}\n", @errorName(err));22 warn("{}\n", @errorName(err));
...@@ -48,7 +44,7 @@ fn badArgs(comptime format: []const u8, args: ...) error {...@@ -48,7 +44,7 @@ fn badArgs(comptime format: []const u8, args: ...) error {
48 return error.InvalidCommandLineArguments;44 return error.InvalidCommandLineArguments;
49}45}
5046
51pub fn main2() %void {47pub fn main2() !void {
52 const allocator = std.heap.c_allocator;48 const allocator = std.heap.c_allocator;
5349
54 const args = try os.argsAlloc(allocator);50 const args = try os.argsAlloc(allocator);
...@@ -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 \\
...@@ -548,7 +544,7 @@ fn printUsage(stream: &io.OutStream) %void {...@@ -548,7 +544,7 @@ fn printUsage(stream: &io.OutStream) %void {
548 );544 );
549}545}
550546
551fn printZen() %void {547fn printZen() !void {
552 var stdout_file = try io.getStdErr();548 var stdout_file = try io.getStdErr();
553 try stdout_file.write(549 try stdout_file.write(
554 \\550 \\
...@@ -569,7 +565,7 @@ fn printZen() %void {...@@ -569,7 +565,7 @@ fn printZen() %void {
569}565}
570566
571/// Caller must free result567/// Caller must free result
572fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const u8) %[]u8 {568fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const u8) ![]u8 {
573 if (zig_install_prefix_arg) |zig_install_prefix| {569 if (zig_install_prefix_arg) |zig_install_prefix| {
574 return testZigInstallPrefix(allocator, zig_install_prefix) catch |err| {570 return testZigInstallPrefix(allocator, zig_install_prefix) catch |err| {
575 warn("No Zig installation found at prefix {}: {}\n", zig_install_prefix_arg, @errorName(err));571 warn("No Zig installation found at prefix {}: {}\n", zig_install_prefix_arg, @errorName(err));
...@@ -585,7 +581,7 @@ fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const...@@ -585,7 +581,7 @@ fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const
585}581}
586582
587/// Caller must free result583/// Caller must free result
588fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) %[]u8 {584fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) ![]u8 {
589 const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig");585 const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig");
590 errdefer allocator.free(test_zig_dir);586 errdefer allocator.free(test_zig_dir);
591587
...@@ -599,7 +595,7 @@ fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) %[]u8...@@ -599,7 +595,7 @@ fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) %[]u8
599}595}
600596
601/// Caller must free result597/// Caller must free result
602fn findZigLibDir(allocator: &mem.Allocator) %[]u8 {598fn findZigLibDir(allocator: &mem.Allocator) ![]u8 {
603 const self_exe_path = try os.selfExeDirPath(allocator);599 const self_exe_path = try os.selfExeDirPath(allocator);
604 defer allocator.free(self_exe_path);600 defer allocator.free(self_exe_path);
605601
src-self-hosted/module.zig+6-5
...@@ -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();
...@@ -198,7 +198,7 @@ pub const Module = struct {...@@ -198,7 +198,7 @@ pub const Module = struct {
198 self.allocator.destroy(self);198 self.allocator.destroy(self);
199 }199 }
200200
201 pub fn build(self: &Module) %void {201 pub fn build(self: &Module) !void {
202 if (self.llvm_argv.len != 0) {202 if (self.llvm_argv.len != 0) {
203 var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.allocator,203 var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.allocator,
204 [][]const []const u8 { [][]const u8{"zig (LLVM option parsing)"}, self.llvm_argv, });204 [][]const []const u8 { [][]const u8{"zig (LLVM option parsing)"}, self.llvm_argv, });
...@@ -263,11 +263,12 @@ pub const Module = struct {...@@ -263,11 +263,12 @@ pub const Module = struct {
263 263
264 }264 }
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 {
271 const is_libc = mem.eql(u8, name, "c");272 const is_libc = mem.eql(u8, name, "c");
272273
273 if (is_libc) {274 if (is_libc) {
...@@ -297,7 +298,7 @@ pub const Module = struct {...@@ -297,7 +298,7 @@ pub const Module = struct {
297 }298 }
298};299};
299300
300fn printError(comptime format: []const u8, args: ...) %void {301fn printError(comptime format: []const u8, args: ...) !void {
301 var stderr_file = try std.io.getStdErr();302 var stderr_file = try std.io.getStdErr();
302 var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);303 var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);
303 const out_stream = &stderr_file_out_stream.stream;304 const out_stream = &stderr_file_out_stream.stream;
src-self-hosted/parser.zig+22-28
...@@ -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,
...@@ -63,7 +61,7 @@ pub const Parser = struct {...@@ -63,7 +61,7 @@ pub const Parser = struct {
63 NullableField: &?&ast.Node,61 NullableField: &?&ast.Node,
64 List: &ArrayList(&ast.Node),62 List: &ArrayList(&ast.Node),
6563
66 pub fn store(self: &const DestPtr, value: &ast.Node) %void {64 pub fn store(self: &const DestPtr, value: &ast.Node) !void {
67 switch (*self) {65 switch (*self) {
68 DestPtr.Field => |ptr| *ptr = value,66 DestPtr.Field => |ptr| *ptr = value,
69 DestPtr.NullableField => |ptr| *ptr = value,67 DestPtr.NullableField => |ptr| *ptr = value,
...@@ -99,7 +97,7 @@ pub const Parser = struct {...@@ -99,7 +97,7 @@ pub const Parser = struct {
9997
100 /// Returns an AST tree, allocated with the parser's allocator.98 /// Returns an AST tree, allocated with the parser's allocator.
101 /// Result should be freed with `freeAst` when done.99 /// Result should be freed with `freeAst` when done.
102 pub fn parse(self: &Parser) %Tree {100 pub fn parse(self: &Parser) !Tree {
103 var stack = self.initUtilityArrayList(State);101 var stack = self.initUtilityArrayList(State);
104 defer self.deinitUtilityArrayList(stack);102 defer self.deinitUtilityArrayList(stack);
105103
...@@ -544,7 +542,7 @@ pub const Parser = struct {...@@ -544,7 +542,7 @@ pub const Parser = struct {
544 }542 }
545 }543 }
546544
547 fn createRoot(self: &Parser) %&ast.NodeRoot {545 fn createRoot(self: &Parser) !&ast.NodeRoot {
548 const node = try self.allocator.create(ast.NodeRoot);546 const node = try self.allocator.create(ast.NodeRoot);
549547
550 *node = ast.NodeRoot {548 *node = ast.NodeRoot {
...@@ -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
...@@ -599,7 +597,7 @@ pub const Parser = struct {...@@ -599,7 +597,7 @@ pub const Parser = struct {
599 return node;597 return node;
600 }598 }
601599
602 fn createParamDecl(self: &Parser) %&ast.NodeParamDecl {600 fn createParamDecl(self: &Parser) !&ast.NodeParamDecl {
603 const node = try self.allocator.create(ast.NodeParamDecl);601 const node = try self.allocator.create(ast.NodeParamDecl);
604602
605 *node = ast.NodeParamDecl {603 *node = ast.NodeParamDecl {
...@@ -613,7 +611,7 @@ pub const Parser = struct {...@@ -613,7 +611,7 @@ pub const Parser = struct {
613 return node;611 return node;
614 }612 }
615613
616 fn createBlock(self: &Parser, begin_token: &const Token) %&ast.NodeBlock {614 fn createBlock(self: &Parser, begin_token: &const Token) !&ast.NodeBlock {
617 const node = try self.allocator.create(ast.NodeBlock);615 const node = try self.allocator.create(ast.NodeBlock);
618616
619 *node = ast.NodeBlock {617 *node = ast.NodeBlock {
...@@ -625,7 +623,7 @@ pub const Parser = struct {...@@ -625,7 +623,7 @@ pub const Parser = struct {
625 return node;623 return node;
626 }624 }
627625
628 fn createInfixOp(self: &Parser, op_token: &const Token, op: &const ast.NodeInfixOp.InfixOp) %&ast.NodeInfixOp {626 fn createInfixOp(self: &Parser, op_token: &const Token, op: &const ast.NodeInfixOp.InfixOp) !&ast.NodeInfixOp {
629 const node = try self.allocator.create(ast.NodeInfixOp);627 const node = try self.allocator.create(ast.NodeInfixOp);
630628
631 *node = ast.NodeInfixOp {629 *node = ast.NodeInfixOp {
...@@ -638,7 +636,7 @@ pub const Parser = struct {...@@ -638,7 +636,7 @@ pub const Parser = struct {
638 return node;636 return node;
639 }637 }
640638
641 fn createPrefixOp(self: &Parser, op_token: &const Token, op: &const ast.NodePrefixOp.PrefixOp) %&ast.NodePrefixOp {639 fn createPrefixOp(self: &Parser, op_token: &const Token, op: &const ast.NodePrefixOp.PrefixOp) !&ast.NodePrefixOp {
642 const node = try self.allocator.create(ast.NodePrefixOp);640 const node = try self.allocator.create(ast.NodePrefixOp);
643641
644 *node = ast.NodePrefixOp {642 *node = ast.NodePrefixOp {
...@@ -650,7 +648,7 @@ pub const Parser = struct {...@@ -650,7 +648,7 @@ pub const Parser = struct {
650 return node;648 return node;
651 }649 }
652650
653 fn createIdentifier(self: &Parser, name_token: &const Token) %&ast.NodeIdentifier {651 fn createIdentifier(self: &Parser, name_token: &const Token) !&ast.NodeIdentifier {
654 const node = try self.allocator.create(ast.NodeIdentifier);652 const node = try self.allocator.create(ast.NodeIdentifier);
655653
656 *node = ast.NodeIdentifier {654 *node = ast.NodeIdentifier {
...@@ -660,7 +658,7 @@ pub const Parser = struct {...@@ -660,7 +658,7 @@ pub const Parser = struct {
660 return node;658 return node;
661 }659 }
662660
663 fn createIntegerLiteral(self: &Parser, token: &const Token) %&ast.NodeIntegerLiteral {661 fn createIntegerLiteral(self: &Parser, token: &const Token) !&ast.NodeIntegerLiteral {
664 const node = try self.allocator.create(ast.NodeIntegerLiteral);662 const node = try self.allocator.create(ast.NodeIntegerLiteral);
665663
666 *node = ast.NodeIntegerLiteral {664 *node = ast.NodeIntegerLiteral {
...@@ -670,7 +668,7 @@ pub const Parser = struct {...@@ -670,7 +668,7 @@ pub const Parser = struct {
670 return node;668 return node;
671 }669 }
672670
673 fn createFloatLiteral(self: &Parser, token: &const Token) %&ast.NodeFloatLiteral {671 fn createFloatLiteral(self: &Parser, token: &const Token) !&ast.NodeFloatLiteral {
674 const node = try self.allocator.create(ast.NodeFloatLiteral);672 const node = try self.allocator.create(ast.NodeFloatLiteral);
675673
676 *node = ast.NodeFloatLiteral {674 *node = ast.NodeFloatLiteral {
...@@ -680,13 +678,13 @@ pub const Parser = struct {...@@ -680,13 +678,13 @@ pub const Parser = struct {
680 return node;678 return node;
681 }679 }
682680
683 fn createAttachIdentifier(self: &Parser, dest_ptr: &const DestPtr, name_token: &const Token) %&ast.NodeIdentifier {681 fn createAttachIdentifier(self: &Parser, dest_ptr: &const DestPtr, name_token: &const Token) !&ast.NodeIdentifier {
684 const node = try self.createIdentifier(name_token);682 const node = try self.createIdentifier(name_token);
685 try dest_ptr.store(&node.base);683 try dest_ptr.store(&node.base);
686 return node;684 return node;
687 }685 }
688686
689 fn createAttachParamDecl(self: &Parser, list: &ArrayList(&ast.Node)) %&ast.NodeParamDecl {687 fn createAttachParamDecl(self: &Parser, list: &ArrayList(&ast.Node)) !&ast.NodeParamDecl {
690 const node = try self.createParamDecl();688 const node = try self.createParamDecl();
691 try list.append(&node.base);689 try list.append(&node.base);
692 return node;690 return node;
...@@ -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);
...@@ -730,13 +728,13 @@ pub const Parser = struct {...@@ -730,13 +728,13 @@ pub const Parser = struct {
730 return error.ParseError;728 return error.ParseError;
731 }729 }
732730
733 fn expectToken(self: &Parser, token: &const Token, id: @TagType(Token.Id)) %void {731 fn expectToken(self: &Parser, token: &const Token, id: @TagType(Token.Id)) !void {
734 if (token.id != id) {732 if (token.id != id) {
735 return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id));733 return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id));
736 }734 }
737 }735 }
738736
739 fn eatToken(self: &Parser, id: @TagType(Token.Id)) %Token {737 fn eatToken(self: &Parser, id: @TagType(Token.Id)) !Token {
740 const token = self.getNextToken();738 const token = self.getNextToken();
741 try self.expectToken(token, id);739 try self.expectToken(token, id);
742 return token;740 return token;
...@@ -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
...@@ -1038,7 +1036,7 @@ pub const Parser = struct {...@@ -1038,7 +1036,7 @@ pub const Parser = struct {
10381036
1039var fixed_buffer_mem: [100 * 1024]u8 = undefined;1037var fixed_buffer_mem: [100 * 1024]u8 = undefined;
10401038
1041fn testParse(source: []const u8, allocator: &mem.Allocator) %[]u8 {1039fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {
1042 var padded_source: [0x100]u8 = undefined;1040 var padded_source: [0x100]u8 = undefined;
1043 std.mem.copy(u8, padded_source[0..source.len], source);1041 std.mem.copy(u8, padded_source[0..source.len], source);
1044 padded_source[source.len + 0] = '\n';1042 padded_source[source.len + 0] = '\n';
...@@ -1058,13 +1056,9 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) %[]u8 {...@@ -1058,13 +1056,9 @@ 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 {
1068 const needed_alloc_count = x: {1062 const needed_alloc_count = x: {
1069 // Try it once with unlimited memory, make sure it works1063 // Try it once with unlimited memory, make sure it works
1070 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);1064 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
src/all_types.hpp+47-21
...@@ -236,7 +236,7 @@ struct ConstExprValue {...@@ -236,7 +236,7 @@ struct ConstExprValue {
236 TypeTableEntry *x_type;236 TypeTableEntry *x_type;
237 ConstExprValue *x_maybe;237 ConstExprValue *x_maybe;
238 ConstErrValue x_err_union;238 ConstErrValue x_err_union;
239 ErrorTableEntry *x_pure_err;239 ErrorTableEntry *x_err_set;
240 BigInt x_enum_tag;240 BigInt x_enum_tag;
241 ConstStructValue x_struct;241 ConstStructValue x_struct;
242 ConstUnionValue x_union;242 ConstUnionValue x_union;
...@@ -353,7 +353,6 @@ enum NodeType {...@@ -353,7 +353,6 @@ enum NodeType {
353 NodeTypeReturnExpr,353 NodeTypeReturnExpr,
354 NodeTypeDefer,354 NodeTypeDefer,
355 NodeTypeVariableDeclaration,355 NodeTypeVariableDeclaration,
356 NodeTypeErrorValueDecl,
357 NodeTypeTestDecl,356 NodeTypeTestDecl,
358 NodeTypeBinOpExpr,357 NodeTypeBinOpExpr,
359 NodeTypeUnwrapErrorExpr,358 NodeTypeUnwrapErrorExpr,
...@@ -393,6 +392,7 @@ enum NodeType {...@@ -393,6 +392,7 @@ enum NodeType {
393 NodeTypeVarLiteral,392 NodeTypeVarLiteral,
394 NodeTypeIfErrorExpr,393 NodeTypeIfErrorExpr,
395 NodeTypeTestExpr,394 NodeTypeTestExpr,
395 NodeTypeErrorSetDecl,
396};396};
397397
398struct AstNodeRoot {398struct AstNodeRoot {
...@@ -424,6 +424,8 @@ struct AstNodeFnProto {...@@ -424,6 +424,8 @@ struct AstNodeFnProto {
424 AstNode *align_expr;424 AstNode *align_expr;
425 // populated if the "section(S)" is present425 // populated if the "section(S)" is present
426 AstNode *section_expr;426 AstNode *section_expr;
427
428 bool auto_err_set;
427};429};
428430
429struct AstNodeFnDef {431struct AstNodeFnDef {
...@@ -486,12 +488,6 @@ struct AstNodeVariableDeclaration {...@@ -486,12 +488,6 @@ struct AstNodeVariableDeclaration {
486 AstNode *section_expr;488 AstNode *section_expr;
487};489};
488490
489struct AstNodeErrorValueDecl {
490 Buf *name;
491
492 ErrorTableEntry *err;
493};
494
495struct AstNodeTestDecl {491struct AstNodeTestDecl {
496 Buf *name;492 Buf *name;
497493
...@@ -514,8 +510,7 @@ enum BinOpType {...@@ -514,8 +510,7 @@ enum BinOpType {
514 BinOpTypeAssignBitAnd,510 BinOpTypeAssignBitAnd,
515 BinOpTypeAssignBitXor,511 BinOpTypeAssignBitXor,
516 BinOpTypeAssignBitOr,512 BinOpTypeAssignBitOr,
517 BinOpTypeAssignBoolAnd,513 BinOpTypeAssignMergeErrorSets,
518 BinOpTypeAssignBoolOr,
519 BinOpTypeBoolOr,514 BinOpTypeBoolOr,
520 BinOpTypeBoolAnd,515 BinOpTypeBoolAnd,
521 BinOpTypeCmpEq,516 BinOpTypeCmpEq,
...@@ -540,6 +535,8 @@ enum BinOpType {...@@ -540,6 +535,8 @@ enum BinOpType {
540 BinOpTypeUnwrapMaybe,535 BinOpTypeUnwrapMaybe,
541 BinOpTypeArrayCat,536 BinOpTypeArrayCat,
542 BinOpTypeArrayMult,537 BinOpTypeArrayMult,
538 BinOpTypeErrorUnion,
539 BinOpTypeMergeErrorSets,
543};540};
544541
545struct AstNodeBinOpExpr {542struct AstNodeBinOpExpr {
...@@ -563,6 +560,7 @@ enum CastOp {...@@ -563,6 +560,7 @@ enum CastOp {
563 CastOpResizeSlice,560 CastOpResizeSlice,
564 CastOpBytesToSlice,561 CastOpBytesToSlice,
565 CastOpNumLitToConcrete,562 CastOpNumLitToConcrete,
563 CastOpErrSet,
566};564};
567565
568struct AstNodeFnCallExpr {566struct AstNodeFnCallExpr {
...@@ -595,7 +593,6 @@ enum PrefixOp {...@@ -595,7 +593,6 @@ enum PrefixOp {
595 PrefixOpNegationWrap,593 PrefixOpNegationWrap,
596 PrefixOpDereference,594 PrefixOpDereference,
597 PrefixOpMaybe,595 PrefixOpMaybe,
598 PrefixOpError,
599 PrefixOpUnwrapMaybe,596 PrefixOpUnwrapMaybe,
600};597};
601598
...@@ -762,6 +759,10 @@ struct AstNodeContainerDecl {...@@ -762,6 +759,10 @@ struct AstNodeContainerDecl {
762 bool auto_enum; // union(enum)759 bool auto_enum; // union(enum)
763};760};
764761
762struct AstNodeErrorSetDecl {
763 ZigList<AstNode *> decls;
764};
765
765struct AstNodeStructField {766struct AstNodeStructField {
766 VisibMod visib_mod;767 VisibMod visib_mod;
767 Buf *name;768 Buf *name;
...@@ -858,7 +859,6 @@ struct AstNode {...@@ -858,7 +859,6 @@ struct AstNode {
858 AstNodeReturnExpr return_expr;859 AstNodeReturnExpr return_expr;
859 AstNodeDefer defer;860 AstNodeDefer defer;
860 AstNodeVariableDeclaration variable_declaration;861 AstNodeVariableDeclaration variable_declaration;
861 AstNodeErrorValueDecl error_value_decl;
862 AstNodeTestDecl test_decl;862 AstNodeTestDecl test_decl;
863 AstNodeBinOpExpr bin_op_expr;863 AstNodeBinOpExpr bin_op_expr;
864 AstNodeCatchExpr unwrap_err_expr;864 AstNodeCatchExpr unwrap_err_expr;
...@@ -899,6 +899,7 @@ struct AstNode {...@@ -899,6 +899,7 @@ struct AstNode {
899 AstNodeArrayType array_type;899 AstNodeArrayType array_type;
900 AstNodeErrorType error_type;900 AstNodeErrorType error_type;
901 AstNodeVarLiteral var_literal;901 AstNodeVarLiteral var_literal;
902 AstNodeErrorSetDecl err_set_decl;
902 } data;903 } data;
903};904};
904905
...@@ -993,8 +994,15 @@ struct TypeTableEntryMaybe {...@@ -993,8 +994,15 @@ struct TypeTableEntryMaybe {
993 TypeTableEntry *child_type;994 TypeTableEntry *child_type;
994};995};
995996
996struct TypeTableEntryError {997struct TypeTableEntryErrorUnion {
997 TypeTableEntry *child_type;998 TypeTableEntry *err_set_type;
999 TypeTableEntry *payload_type;
1000};
1001
1002struct TypeTableEntryErrorSet {
1003 uint32_t err_count;
1004 ErrorTableEntry **errors;
1005 FnTableEntry *infer_fn;
998};1006};
9991007
1000struct TypeTableEntryEnum {1008struct TypeTableEntryEnum {
...@@ -1097,7 +1105,7 @@ enum TypeTableEntryId {...@@ -1097,7 +1105,7 @@ enum TypeTableEntryId {
1097 TypeTableEntryIdNullLit,1105 TypeTableEntryIdNullLit,
1098 TypeTableEntryIdMaybe,1106 TypeTableEntryIdMaybe,
1099 TypeTableEntryIdErrorUnion,1107 TypeTableEntryIdErrorUnion,
1100 TypeTableEntryIdPureError,1108 TypeTableEntryIdErrorSet,
1101 TypeTableEntryIdEnum,1109 TypeTableEntryIdEnum,
1102 TypeTableEntryIdUnion,1110 TypeTableEntryIdUnion,
1103 TypeTableEntryIdFn,1111 TypeTableEntryIdFn,
...@@ -1126,7 +1134,8 @@ struct TypeTableEntry {...@@ -1126,7 +1134,8 @@ struct TypeTableEntry {
1126 TypeTableEntryArray array;1134 TypeTableEntryArray array;
1127 TypeTableEntryStruct structure;1135 TypeTableEntryStruct structure;
1128 TypeTableEntryMaybe maybe;1136 TypeTableEntryMaybe maybe;
1129 TypeTableEntryError error;1137 TypeTableEntryErrorUnion error_union;
1138 TypeTableEntryErrorSet error_set;
1130 TypeTableEntryEnum enumeration;1139 TypeTableEntryEnum enumeration;
1131 TypeTableEntryUnion unionation;1140 TypeTableEntryUnion unionation;
1132 TypeTableEntryFn fn;1141 TypeTableEntryFn fn;
...@@ -1136,7 +1145,6 @@ struct TypeTableEntry {...@@ -1136,7 +1145,6 @@ struct TypeTableEntry {
1136 // use these fields to make sure we don't duplicate type table entries for the same type1145 // use these fields to make sure we don't duplicate type table entries for the same type
1137 TypeTableEntry *pointer_parent[2]; // [0 - mut, 1 - const]1146 TypeTableEntry *pointer_parent[2]; // [0 - mut, 1 - const]
1138 TypeTableEntry *maybe_parent;1147 TypeTableEntry *maybe_parent;
1139 TypeTableEntry *error_parent;
1140 // If we generate a constant name value for this type, we memoize it here.1148 // If we generate a constant name value for this type, we memoize it here.
1141 // The type of this is array1149 // The type of this is array
1142 ConstExprValue *cached_const_name_val;1150 ConstExprValue *cached_const_name_val;
...@@ -1340,6 +1348,10 @@ struct TypeId {...@@ -1340,6 +1348,10 @@ struct TypeId {
1340 bool is_signed;1348 bool is_signed;
1341 uint32_t bit_count;1349 uint32_t bit_count;
1342 } integer;1350 } integer;
1351 struct {
1352 TypeTableEntry *err_set_type;
1353 TypeTableEntry *payload_type;
1354 } error_union;
1343 } data;1355 } data;
1344};1356};
13451357
...@@ -1481,7 +1493,7 @@ struct CodeGen {...@@ -1481,7 +1493,7 @@ struct CodeGen {
1481 TypeTableEntry *entry_undef;1493 TypeTableEntry *entry_undef;
1482 TypeTableEntry *entry_null;1494 TypeTableEntry *entry_null;
1483 TypeTableEntry *entry_var;1495 TypeTableEntry *entry_var;
1484 TypeTableEntry *entry_pure_error;1496 TypeTableEntry *entry_global_error_set;
1485 TypeTableEntry *entry_arg_tuple;1497 TypeTableEntry *entry_arg_tuple;
1486 } builtin_types;1498 } builtin_types;
14871499
...@@ -1570,7 +1582,6 @@ struct CodeGen {...@@ -1570,7 +1582,6 @@ struct CodeGen {
1570 LLVMValueRef return_address_fn_val;1582 LLVMValueRef return_address_fn_val;
1571 LLVMValueRef frame_address_fn_val;1583 LLVMValueRef frame_address_fn_val;
1572 bool error_during_imports;1584 bool error_during_imports;
1573 TypeTableEntry *err_tag_type;
15741585
1575 const char **clang_argv;1586 const char **clang_argv;
1576 size_t clang_argv_len;1587 size_t clang_argv_len;
...@@ -1584,7 +1595,9 @@ struct CodeGen {...@@ -1584,7 +1595,9 @@ struct CodeGen {
15841595
1585 bool each_lib_rpath;1596 bool each_lib_rpath;
15861597
1587 ZigList<AstNode *> error_decls;1598 TypeTableEntry *err_tag_type;
1599 ZigList<ZigLLVMDIEnumerator *> err_enumerators;
1600 ZigList<ErrorTableEntry *> errors_by_index;
1588 bool generate_error_name_table;1601 bool generate_error_name_table;
1589 LLVMValueRef err_name_table;1602 LLVMValueRef err_name_table;
1590 size_t largest_err_name_len;1603 size_t largest_err_name_len;
...@@ -1617,6 +1630,10 @@ struct CodeGen {...@@ -1617,6 +1630,10 @@ struct CodeGen {
1617 TypeTableEntry *align_amt_type;1630 TypeTableEntry *align_amt_type;
1618 TypeTableEntry *stack_trace_type;1631 TypeTableEntry *stack_trace_type;
1619 TypeTableEntry *ptr_to_stack_trace_type;1632 TypeTableEntry *ptr_to_stack_trace_type;
1633
1634 ZigList<ZigLLVMDIType **> error_di_types;
1635
1636 ZigList<Buf *> forbidden_libs;
1620};1637};
16211638
1622enum VarLinkage {1639enum VarLinkage {
...@@ -1653,6 +1670,7 @@ struct ErrorTableEntry {...@@ -1653,6 +1670,7 @@ struct ErrorTableEntry {
1653 Buf name;1670 Buf name;
1654 uint32_t value;1671 uint32_t value;
1655 AstNode *decl_node;1672 AstNode *decl_node;
1673 TypeTableEntry *set_with_only_this_in_it;
1656 // If we generate a constant error name value for this error, we memoize it here.1674 // If we generate a constant error name value for this error, we memoize it here.
1657 // The type of this is array1675 // The type of this is array
1658 ConstExprValue *cached_error_name_val;1676 ConstExprValue *cached_error_name_val;
...@@ -1920,6 +1938,7 @@ enum IrInstructionId {...@@ -1920,6 +1938,7 @@ enum IrInstructionId {
1920 IrInstructionIdArgType,1938 IrInstructionIdArgType,
1921 IrInstructionIdExport,1939 IrInstructionIdExport,
1922 IrInstructionIdErrorReturnTrace,1940 IrInstructionIdErrorReturnTrace,
1941 IrInstructionIdErrorUnion,
1923};1942};
19241943
1925struct IrInstruction {1944struct IrInstruction {
...@@ -1996,7 +2015,6 @@ enum IrUnOp {...@@ -1996,7 +2015,6 @@ enum IrUnOp {
1996 IrUnOpNegation,2015 IrUnOpNegation,
1997 IrUnOpNegationWrap,2016 IrUnOpNegationWrap,
1998 IrUnOpDereference,2017 IrUnOpDereference,
1999 IrUnOpError,
2000 IrUnOpMaybe,2018 IrUnOpMaybe,
2001};2019};
20022020
...@@ -2039,6 +2057,7 @@ enum IrBinOp {...@@ -2039,6 +2057,7 @@ enum IrBinOp {
2039 IrBinOpRemMod,2057 IrBinOpRemMod,
2040 IrBinOpArrayCat,2058 IrBinOpArrayCat,
2041 IrBinOpArrayMult,2059 IrBinOpArrayMult,
2060 IrBinOpMergeErrorSets,
2042};2061};
20432062
2044struct IrInstructionBinOp {2063struct IrInstructionBinOp {
...@@ -2750,6 +2769,13 @@ struct IrInstructionErrorReturnTrace {...@@ -2750,6 +2769,13 @@ struct IrInstructionErrorReturnTrace {
2750 IrInstruction base;2769 IrInstruction base;
2751};2770};
27522771
2772struct IrInstructionErrorUnion {
2773 IrInstruction base;
2774
2775 IrInstruction *err_set;
2776 IrInstruction *payload;
2777};
2778
2753static const size_t slice_ptr_index = 0;2779static const size_t slice_ptr_index = 0;
2754static const size_t slice_len_index = 1;2780static const size_t slice_len_index = 1;
27552781
src/analyze.cpp+169-201
...@@ -224,7 +224,7 @@ bool type_is_complete(TypeTableEntry *type_entry) {...@@ -224,7 +224,7 @@ bool type_is_complete(TypeTableEntry *type_entry) {
224 case TypeTableEntryIdNullLit:224 case TypeTableEntryIdNullLit:
225 case TypeTableEntryIdMaybe:225 case TypeTableEntryIdMaybe:
226 case TypeTableEntryIdErrorUnion:226 case TypeTableEntryIdErrorUnion:
227 case TypeTableEntryIdPureError:227 case TypeTableEntryIdErrorSet:
228 case TypeTableEntryIdFn:228 case TypeTableEntryIdFn:
229 case TypeTableEntryIdNamespace:229 case TypeTableEntryIdNamespace:
230 case TypeTableEntryIdBlock:230 case TypeTableEntryIdBlock:
...@@ -260,7 +260,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) {...@@ -260,7 +260,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) {
260 case TypeTableEntryIdNullLit:260 case TypeTableEntryIdNullLit:
261 case TypeTableEntryIdMaybe:261 case TypeTableEntryIdMaybe:
262 case TypeTableEntryIdErrorUnion:262 case TypeTableEntryIdErrorUnion:
263 case TypeTableEntryIdPureError:263 case TypeTableEntryIdErrorSet:
264 case TypeTableEntryIdFn:264 case TypeTableEntryIdFn:
265 case TypeTableEntryIdNamespace:265 case TypeTableEntryIdNamespace:
266 case TypeTableEntryIdBlock:266 case TypeTableEntryIdBlock:
...@@ -514,29 +514,47 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {...@@ -514,29 +514,47 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
514 }514 }
515}515}
516516
517TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {517TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, TypeTableEntry *payload_type) {
518 if (child_type->error_parent)518 assert(err_set_type->id == TypeTableEntryIdErrorSet);
519 return child_type->error_parent;519 assert(!type_is_invalid(payload_type));
520
521 TypeId type_id = {};
522 type_id.id = TypeTableEntryIdErrorUnion;
523 type_id.data.error_union.err_set_type = err_set_type;
524 type_id.data.error_union.payload_type = payload_type;
525
526 auto existing_entry = g->type_table.maybe_get(type_id);
527 if (existing_entry) {
528 return existing_entry->value;
529 }
520530
521 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion);531 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion);
522 entry->is_copyable = true;532 entry->is_copyable = true;
523 assert(child_type->type_ref);533 assert(payload_type->di_type);
524 assert(child_type->di_type);534 ensure_complete_type(g, payload_type);
525 ensure_complete_type(g, child_type);
526535
527 buf_resize(&entry->name, 0);536 buf_resize(&entry->name, 0);
528 buf_appendf(&entry->name, "%%%s", buf_ptr(&child_type->name));537 buf_appendf(&entry->name, "%s!%s", buf_ptr(&err_set_type->name), buf_ptr(&payload_type->name));
529538
530 entry->data.error.child_type = child_type;539 entry->data.error_union.err_set_type = err_set_type;
531540 entry->data.error_union.payload_type = payload_type;
532 if (!type_has_bits(child_type)) {
533 entry->type_ref = g->err_tag_type->type_ref;
534 entry->di_type = g->err_tag_type->di_type;
535541
542 if (!type_has_bits(payload_type)) {
543 if (type_has_bits(err_set_type)) {
544 entry->type_ref = err_set_type->type_ref;
545 entry->di_type = err_set_type->di_type;
546 g->error_di_types.append(&entry->di_type);
547 } else {
548 entry->zero_bits = true;
549 entry->di_type = g->builtin_types.entry_void->di_type;
550 }
551 } else if (!type_has_bits(err_set_type)) {
552 entry->type_ref = payload_type->type_ref;
553 entry->di_type = payload_type->di_type;
536 } else {554 } else {
537 LLVMTypeRef elem_types[] = {555 LLVMTypeRef elem_types[] = {
538 g->err_tag_type->type_ref,556 err_set_type->type_ref,
539 child_type->type_ref,557 payload_type->type_ref,
540 };558 };
541 entry->type_ref = LLVMStructType(elem_types, 2, false);559 entry->type_ref = LLVMStructType(elem_types, 2, false);
542560
...@@ -547,12 +565,12 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {...@@ -547,12 +565,12 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
547 ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name),565 ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name),
548 compile_unit_scope, di_file, line);566 compile_unit_scope, di_file, line);
549567
550 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, g->err_tag_type->type_ref);568 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, err_set_type->type_ref);
551 uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, g->err_tag_type->type_ref);569 uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, err_set_type->type_ref);
552 uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, err_union_err_index);570 uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, err_union_err_index);
553571
554 uint64_t value_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, child_type->type_ref);572 uint64_t value_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, payload_type->type_ref);
555 uint64_t value_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, child_type->type_ref);573 uint64_t value_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, payload_type->type_ref);
556 uint64_t value_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref,574 uint64_t value_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref,
557 err_union_payload_index);575 err_union_payload_index);
558576
...@@ -565,13 +583,13 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {...@@ -565,13 +583,13 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
565 tag_debug_size_in_bits,583 tag_debug_size_in_bits,
566 tag_debug_align_in_bits,584 tag_debug_align_in_bits,
567 tag_offset_in_bits,585 tag_offset_in_bits,
568 0, child_type->di_type),586 0, err_set_type->di_type),
569 ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),587 ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),
570 "value", di_file, line,588 "value", di_file, line,
571 value_debug_size_in_bits,589 value_debug_size_in_bits,
572 value_debug_align_in_bits,590 value_debug_align_in_bits,
573 value_offset_in_bits,591 value_offset_in_bits,
574 0, child_type->di_type),592 0, payload_type->di_type),
575 };593 };
576594
577 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,595 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
...@@ -587,7 +605,7 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {...@@ -587,7 +605,7 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
587 entry->di_type = replacement_di_type;605 entry->di_type = replacement_di_type;
588 }606 }
589607
590 child_type->error_parent = entry;608 g->type_table.put(type_id, entry);
591 return entry;609 return entry;
592}610}
593611
...@@ -937,7 +955,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -937,7 +955,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
937 handle_is_ptr(fn_type_id->return_type);955 handle_is_ptr(fn_type_id->return_type);
938 bool prefix_arg_error_return_trace = g->have_err_ret_tracing &&956 bool prefix_arg_error_return_trace = g->have_err_ret_tracing &&
939 (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion || 957 (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion ||
940 fn_type_id->return_type->id == TypeTableEntryIdPureError);958 fn_type_id->return_type->id == TypeTableEntryIdErrorSet);
941 // +1 for maybe making the first argument the return value959 // +1 for maybe making the first argument the return value
942 // +1 for maybe last argument the error return trace960 // +1 for maybe last argument the error return trace
943 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(2 + fn_type_id->param_count);961 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(2 + fn_type_id->param_count);
...@@ -1177,7 +1195,7 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {...@@ -1177,7 +1195,7 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
1177 case TypeTableEntryIdUndefLit:1195 case TypeTableEntryIdUndefLit:
1178 case TypeTableEntryIdNullLit:1196 case TypeTableEntryIdNullLit:
1179 case TypeTableEntryIdErrorUnion:1197 case TypeTableEntryIdErrorUnion:
1180 case TypeTableEntryIdPureError:1198 case TypeTableEntryIdErrorSet:
1181 case TypeTableEntryIdNamespace:1199 case TypeTableEntryIdNamespace:
1182 case TypeTableEntryIdBlock:1200 case TypeTableEntryIdBlock:
1183 case TypeTableEntryIdBoundFn:1201 case TypeTableEntryIdBoundFn:
...@@ -1218,7 +1236,7 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {...@@ -1218,7 +1236,7 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
1218 case TypeTableEntryIdUndefLit:1236 case TypeTableEntryIdUndefLit:
1219 case TypeTableEntryIdNullLit:1237 case TypeTableEntryIdNullLit:
1220 case TypeTableEntryIdErrorUnion:1238 case TypeTableEntryIdErrorUnion:
1221 case TypeTableEntryIdPureError:1239 case TypeTableEntryIdErrorSet:
1222 case TypeTableEntryIdNamespace:1240 case TypeTableEntryIdNamespace:
1223 case TypeTableEntryIdBlock:1241 case TypeTableEntryIdBlock:
1224 case TypeTableEntryIdBoundFn:1242 case TypeTableEntryIdBoundFn:
...@@ -1263,7 +1281,23 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {...@@ -1263,7 +1281,23 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
1263 zig_unreachable();1281 zig_unreachable();
1264}1282}
12651283
1266static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope) {1284TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry) {
1285 TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet);
1286 buf_resize(&err_set_type->name, 0);
1287 buf_appendf(&err_set_type->name, "@typeOf(%s).ReturnType.ErrorSet", buf_ptr(&fn_entry->symbol_name));
1288 err_set_type->is_copyable = true;
1289 err_set_type->type_ref = g->builtin_types.entry_global_error_set->type_ref;
1290 err_set_type->di_type = g->builtin_types.entry_global_error_set->di_type;
1291 err_set_type->data.error_set.err_count = 0;
1292 err_set_type->data.error_set.errors = nullptr;
1293 err_set_type->data.error_set.infer_fn = fn_entry;
1294
1295 g->error_di_types.append(&err_set_type->di_type);
1296
1297 return err_set_type;
1298}
1299
1300static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope, FnTableEntry *fn_entry) {
1267 assert(proto_node->type == NodeTypeFnProto);1301 assert(proto_node->type == NodeTypeFnProto);
1268 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;1302 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
12691303
...@@ -1359,7 +1393,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1359,7 +1393,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1359 case TypeTableEntryIdStruct:1393 case TypeTableEntryIdStruct:
1360 case TypeTableEntryIdMaybe:1394 case TypeTableEntryIdMaybe:
1361 case TypeTableEntryIdErrorUnion:1395 case TypeTableEntryIdErrorUnion:
1362 case TypeTableEntryIdPureError:1396 case TypeTableEntryIdErrorSet:
1363 case TypeTableEntryIdEnum:1397 case TypeTableEntryIdEnum:
1364 case TypeTableEntryIdUnion:1398 case TypeTableEntryIdUnion:
1365 case TypeTableEntryIdFn:1399 case TypeTableEntryIdFn:
...@@ -1382,13 +1416,19 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1382,13 +1416,19 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1382 }1416 }
1383 }1417 }
13841418
1385 fn_type_id.return_type = (fn_proto->return_type == nullptr) ?1419 TypeTableEntry *specified_return_type = analyze_type_expr(g, child_scope, fn_proto->return_type);
1386 g->builtin_types.entry_void : analyze_type_expr(g, child_scope, fn_proto->return_type);1420 if (type_is_invalid(specified_return_type)) {
13871421 fn_type_id.return_type = g->builtin_types.entry_invalid;
1388 if (type_is_invalid(fn_type_id.return_type)) {
1389 return g->builtin_types.entry_invalid;1422 return g->builtin_types.entry_invalid;
1390 }1423 }
13911424
1425 if (fn_proto->auto_err_set) {
1426 TypeTableEntry *inferred_err_set_type = get_auto_err_set_type(g, fn_entry);
1427 fn_type_id.return_type = get_error_union_type(g, inferred_err_set_type, specified_return_type);
1428 } else {
1429 fn_type_id.return_type = specified_return_type;
1430 }
1431
1392 if (fn_type_id.cc != CallingConventionUnspecified && !type_allowed_in_extern(g, fn_type_id.return_type)) {1432 if (fn_type_id.cc != CallingConventionUnspecified && !type_allowed_in_extern(g, fn_type_id.return_type)) {
1393 add_node_error(g, fn_proto->return_type,1433 add_node_error(g, fn_proto->return_type,
1394 buf_sprintf("return type '%s' not allowed in function with calling convention '%s'",1434 buf_sprintf("return type '%s' not allowed in function with calling convention '%s'",
...@@ -1434,7 +1474,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1434,7 +1474,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1434 case TypeTableEntryIdStruct:1474 case TypeTableEntryIdStruct:
1435 case TypeTableEntryIdMaybe:1475 case TypeTableEntryIdMaybe:
1436 case TypeTableEntryIdErrorUnion:1476 case TypeTableEntryIdErrorUnion:
1437 case TypeTableEntryIdPureError:1477 case TypeTableEntryIdErrorSet:
1438 case TypeTableEntryIdEnum:1478 case TypeTableEntryIdEnum:
1439 case TypeTableEntryIdUnion:1479 case TypeTableEntryIdUnion:
1440 case TypeTableEntryIdFn:1480 case TypeTableEntryIdFn:
...@@ -2756,7 +2796,8 @@ TypeTableEntry *get_test_fn_type(CodeGen *g) {...@@ -2756,7 +2796,8 @@ TypeTableEntry *get_test_fn_type(CodeGen *g) {
2756 return g->test_fn_type;2796 return g->test_fn_type;
27572797
2758 FnTypeId fn_type_id = {0};2798 FnTypeId fn_type_id = {0};
2759 fn_type_id.return_type = get_error_type(g, g->builtin_types.entry_void);2799 fn_type_id.return_type = get_error_union_type(g, g->builtin_types.entry_global_error_set,
2800 g->builtin_types.entry_void);
2760 g->test_fn_type = get_fn_type(g, &fn_type_id);2801 g->test_fn_type = get_fn_type(g, &fn_type_id);
2761 return g->test_fn_type;2802 return g->test_fn_type;
2762}2803}
...@@ -2824,7 +2865,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {...@@ -2824,7 +2865,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
28242865
2825 Scope *child_scope = fn_table_entry->fndef_scope ? &fn_table_entry->fndef_scope->base : tld_fn->base.parent_scope;2866 Scope *child_scope = fn_table_entry->fndef_scope ? &fn_table_entry->fndef_scope->base : tld_fn->base.parent_scope;
28262867
2827 fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope);2868 fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope, fn_table_entry);
28282869
2829 if (fn_proto->section_expr != nullptr) {2870 if (fn_proto->section_expr != nullptr) {
2830 if (fn_table_entry->body_node == nullptr) {2871 if (fn_table_entry->body_node == nullptr) {
...@@ -2949,29 +2990,6 @@ static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope...@@ -2949,29 +2990,6 @@ static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope
2949 g->resolve_queue.append(&tld_fn->base);2990 g->resolve_queue.append(&tld_fn->base);
2950}2991}
29512992
2952static void preview_error_value_decl(CodeGen *g, AstNode *node) {
2953 assert(node->type == NodeTypeErrorValueDecl);
2954
2955 ErrorTableEntry *err = allocate<ErrorTableEntry>(1);
2956
2957 err->decl_node = node;
2958 buf_init_from_buf(&err->name, node->data.error_value_decl.name);
2959
2960 auto existing_entry = g->error_table.maybe_get(&err->name);
2961 if (existing_entry) {
2962 // duplicate error definitions allowed and they get the same value
2963 err->value = existing_entry->value->value;
2964 } else {
2965 size_t error_value_count = g->error_decls.length;
2966 assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)g->err_tag_type->data.integral.bit_count));
2967 err->value = (uint32_t)error_value_count;
2968 g->error_decls.append(node);
2969 g->error_table.put(&err->name, err);
2970 }
2971
2972 node->data.error_value_decl.err = err;
2973}
2974
2975static void preview_comptime_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) {2993static void preview_comptime_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) {
2976 assert(node->type == NodeTypeCompTime);2994 assert(node->type == NodeTypeCompTime);
29772995
...@@ -3045,10 +3063,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {...@@ -3045,10 +3063,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
3045 import->use_decls.append(node);3063 import->use_decls.append(node);
3046 break;3064 break;
3047 }3065 }
3048 case NodeTypeErrorValueDecl:
3049 // error value declarations do not depend on other top level decls
3050 preview_error_value_decl(g, node);
3051 break;
3052 case NodeTypeTestDecl:3066 case NodeTypeTestDecl:
3053 preview_test_decl(g, node, decls_scope);3067 preview_test_decl(g, node, decls_scope);
3054 break;3068 break;
...@@ -3097,6 +3111,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {...@@ -3097,6 +3111,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
3097 case NodeTypeVarLiteral:3111 case NodeTypeVarLiteral:
3098 case NodeTypeIfErrorExpr:3112 case NodeTypeIfErrorExpr:
3099 case NodeTypeTestExpr:3113 case NodeTypeTestExpr:
3114 case NodeTypeErrorSetDecl:
3100 zig_unreachable();3115 zig_unreachable();
3101 }3116 }
3102}3117}
...@@ -3147,7 +3162,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt...@@ -3147,7 +3162,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
3147 case TypeTableEntryIdStruct:3162 case TypeTableEntryIdStruct:
3148 case TypeTableEntryIdMaybe:3163 case TypeTableEntryIdMaybe:
3149 case TypeTableEntryIdErrorUnion:3164 case TypeTableEntryIdErrorUnion:
3150 case TypeTableEntryIdPureError:3165 case TypeTableEntryIdErrorSet:
3151 case TypeTableEntryIdEnum:3166 case TypeTableEntryIdEnum:
3152 case TypeTableEntryIdUnion:3167 case TypeTableEntryIdUnion:
3153 case TypeTableEntryIdFn:3168 case TypeTableEntryIdFn:
...@@ -3362,108 +3377,6 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *so...@@ -3362,108 +3377,6 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *so
3362 g->tld_ref_source_node_stack.pop();3377 g->tld_ref_source_node_stack.pop();
3363}3378}
33643379
3365bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type) {
3366 if (expected_type == actual_type)
3367 return true;
3368
3369 // pointer const
3370 if (expected_type->id == TypeTableEntryIdPointer &&
3371 actual_type->id == TypeTableEntryIdPointer &&
3372 (!actual_type->data.pointer.is_const || expected_type->data.pointer.is_const) &&
3373 (!actual_type->data.pointer.is_volatile || expected_type->data.pointer.is_volatile) &&
3374 actual_type->data.pointer.bit_offset == expected_type->data.pointer.bit_offset &&
3375 actual_type->data.pointer.unaligned_bit_count == expected_type->data.pointer.unaligned_bit_count &&
3376 actual_type->data.pointer.alignment >= expected_type->data.pointer.alignment)
3377 {
3378 return types_match_const_cast_only(expected_type->data.pointer.child_type,
3379 actual_type->data.pointer.child_type);
3380 }
3381
3382 // slice const
3383 if (is_slice(expected_type) && is_slice(actual_type)) {
3384 TypeTableEntry *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index].type_entry;
3385 TypeTableEntry *expected_ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry;
3386 if ((!actual_ptr_type->data.pointer.is_const || expected_ptr_type->data.pointer.is_const) &&
3387 (!actual_ptr_type->data.pointer.is_volatile || expected_ptr_type->data.pointer.is_volatile) &&
3388 actual_ptr_type->data.pointer.bit_offset == expected_ptr_type->data.pointer.bit_offset &&
3389 actual_ptr_type->data.pointer.unaligned_bit_count == expected_ptr_type->data.pointer.unaligned_bit_count &&
3390 actual_ptr_type->data.pointer.alignment >= expected_ptr_type->data.pointer.alignment)
3391 {
3392 return types_match_const_cast_only(expected_ptr_type->data.pointer.child_type,
3393 actual_ptr_type->data.pointer.child_type);
3394 }
3395 }
3396
3397 // maybe
3398 if (expected_type->id == TypeTableEntryIdMaybe &&
3399 actual_type->id == TypeTableEntryIdMaybe)
3400 {
3401 return types_match_const_cast_only(
3402 expected_type->data.maybe.child_type,
3403 actual_type->data.maybe.child_type);
3404 }
3405
3406 // error
3407 if (expected_type->id == TypeTableEntryIdErrorUnion &&
3408 actual_type->id == TypeTableEntryIdErrorUnion)
3409 {
3410 return types_match_const_cast_only(
3411 expected_type->data.error.child_type,
3412 actual_type->data.error.child_type);
3413 }
3414
3415 // fn
3416 if (expected_type->id == TypeTableEntryIdFn &&
3417 actual_type->id == TypeTableEntryIdFn)
3418 {
3419 if (expected_type->data.fn.fn_type_id.alignment > actual_type->data.fn.fn_type_id.alignment) {
3420 return false;
3421 }
3422 if (expected_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) {
3423 return false;
3424 }
3425 if (expected_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {
3426 return false;
3427 }
3428 if (expected_type->data.fn.is_generic != actual_type->data.fn.is_generic) {
3429 return false;
3430 }
3431 if (!expected_type->data.fn.is_generic &&
3432 actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable &&
3433 !types_match_const_cast_only(
3434 expected_type->data.fn.fn_type_id.return_type,
3435 actual_type->data.fn.fn_type_id.return_type))
3436 {
3437 return false;
3438 }
3439 if (expected_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {
3440 return false;
3441 }
3442 if (expected_type->data.fn.fn_type_id.next_param_index != actual_type->data.fn.fn_type_id.next_param_index) {
3443 return false;
3444 }
3445 assert(expected_type->data.fn.is_generic ||
3446 expected_type->data.fn.fn_type_id.next_param_index == expected_type->data.fn.fn_type_id.param_count);
3447 for (size_t i = 0; i < expected_type->data.fn.fn_type_id.next_param_index; i += 1) {
3448 // note it's reversed for parameters
3449 FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i];
3450 FnTypeParamInfo *expected_param_info = &expected_type->data.fn.fn_type_id.param_info[i];
3451
3452 if (!types_match_const_cast_only(actual_param_info->type, expected_param_info->type)) {
3453 return false;
3454 }
3455
3456 if (expected_param_info->is_noalias != actual_param_info->is_noalias) {
3457 return false;
3458 }
3459 }
3460 return true;
3461 }
3462
3463
3464 return false;
3465}
3466
3467Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) {3380Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) {
3468 // we must resolve all the use decls3381 // we must resolve all the use decls
3469 ImportTableEntry *import = get_scope_import(scope);3382 ImportTableEntry *import = get_scope_import(scope);
...@@ -3625,7 +3538,7 @@ static bool is_container(TypeTableEntry *type_entry) {...@@ -3625,7 +3538,7 @@ static bool is_container(TypeTableEntry *type_entry) {
3625 case TypeTableEntryIdNullLit:3538 case TypeTableEntryIdNullLit:
3626 case TypeTableEntryIdMaybe:3539 case TypeTableEntryIdMaybe:
3627 case TypeTableEntryIdErrorUnion:3540 case TypeTableEntryIdErrorUnion:
3628 case TypeTableEntryIdPureError:3541 case TypeTableEntryIdErrorSet:
3629 case TypeTableEntryIdFn:3542 case TypeTableEntryIdFn:
3630 case TypeTableEntryIdNamespace:3543 case TypeTableEntryIdNamespace:
3631 case TypeTableEntryIdBlock:3544 case TypeTableEntryIdBlock:
...@@ -3673,7 +3586,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {...@@ -3673,7 +3586,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
3673 case TypeTableEntryIdNullLit:3586 case TypeTableEntryIdNullLit:
3674 case TypeTableEntryIdMaybe:3587 case TypeTableEntryIdMaybe:
3675 case TypeTableEntryIdErrorUnion:3588 case TypeTableEntryIdErrorUnion:
3676 case TypeTableEntryIdPureError:3589 case TypeTableEntryIdErrorSet:
3677 case TypeTableEntryIdFn:3590 case TypeTableEntryIdFn:
3678 case TypeTableEntryIdNamespace:3591 case TypeTableEntryIdNamespace:
3679 case TypeTableEntryIdBlock:3592 case TypeTableEntryIdBlock:
...@@ -3765,6 +3678,27 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari...@@ -3765,6 +3678,27 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari
3765 }3678 }
3766}3679}
37673680
3681static bool analyze_resolve_inferred_error_set(CodeGen *g, TypeTableEntry *err_set_type, AstNode *source_node) {
3682 FnTableEntry *infer_fn = err_set_type->data.error_set.infer_fn;
3683 if (infer_fn != nullptr) {
3684 if (infer_fn->anal_state == FnAnalStateInvalid) {
3685 return false;
3686 } else if (infer_fn->anal_state == FnAnalStateReady) {
3687 analyze_fn_body(g, infer_fn);
3688 if (err_set_type->data.error_set.infer_fn != nullptr) {
3689 assert(g->errors.length != 0);
3690 return false;
3691 }
3692 } else {
3693 add_node_error(g, source_node,
3694 buf_sprintf("cannot resolve inferred error set '%s': function '%s' not fully analyzed yet",
3695 buf_ptr(&err_set_type->name), buf_ptr(&err_set_type->data.error_set.infer_fn->symbol_name)));
3696 return false;
3697 }
3698 }
3699 return true;
3700}
3701
3768void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_type_node) {3702void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_type_node) {
3769 TypeTableEntry *fn_type = fn_table_entry->type_entry;3703 TypeTableEntry *fn_type = fn_table_entry->type_entry;
3770 assert(!fn_type->data.fn.is_generic);3704 assert(!fn_type->data.fn.is_generic);
...@@ -3774,14 +3708,49 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ...@@ -3774,14 +3708,49 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
3774 &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node);3708 &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node);
3775 fn_table_entry->implicit_return_type = block_return_type;3709 fn_table_entry->implicit_return_type = block_return_type;
37763710
3777 if (block_return_type->id == TypeTableEntryIdInvalid ||3711 if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) {
3778 fn_table_entry->analyzed_executable.invalid)
3779 {
3780 assert(g->errors.length > 0);3712 assert(g->errors.length > 0);
3781 fn_table_entry->anal_state = FnAnalStateInvalid;3713 fn_table_entry->anal_state = FnAnalStateInvalid;
3782 return;3714 return;
3783 }3715 }
37843716
3717 if (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) {
3718 TypeTableEntry *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;
3719 if (return_err_set_type->data.error_set.infer_fn != nullptr) {
3720 TypeTableEntry *inferred_err_set_type;
3721 if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorSet) {
3722 inferred_err_set_type = fn_table_entry->implicit_return_type;
3723 } else if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorUnion) {
3724 inferred_err_set_type = fn_table_entry->implicit_return_type->data.error_union.err_set_type;
3725 } else {
3726 add_node_error(g, return_type_node,
3727 buf_sprintf("function with inferred error set must return at least one possible error"));
3728 fn_table_entry->anal_state = FnAnalStateInvalid;
3729 return;
3730 }
3731
3732 if (inferred_err_set_type->data.error_set.infer_fn != nullptr) {
3733 if (!analyze_resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {
3734 fn_table_entry->anal_state = FnAnalStateInvalid;
3735 return;
3736 }
3737 }
3738
3739 return_err_set_type->data.error_set.infer_fn = nullptr;
3740 if (type_is_global_error_set(inferred_err_set_type)) {
3741 return_err_set_type->data.error_set.err_count = UINT32_MAX;
3742 } else {
3743 return_err_set_type->data.error_set.err_count = inferred_err_set_type->data.error_set.err_count;
3744 if (inferred_err_set_type->data.error_set.err_count > 0) {
3745 return_err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(inferred_err_set_type->data.error_set.err_count);
3746 for (uint32_t i = 0; i < inferred_err_set_type->data.error_set.err_count; i += 1) {
3747 return_err_set_type->data.error_set.errors[i] = inferred_err_set_type->data.error_set.errors[i];
3748 }
3749 }
3750 }
3751 }
3752 }
3753
3785 if (g->verbose_ir) {3754 if (g->verbose_ir) {
3786 fprintf(stderr, "{ // (analyzed)\n");3755 fprintf(stderr, "{ // (analyzed)\n");
3787 ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4);3756 ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4);
...@@ -3791,7 +3760,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ...@@ -3791,7 +3760,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
3791 fn_table_entry->anal_state = FnAnalStateComplete;3760 fn_table_entry->anal_state = FnAnalStateComplete;
3792}3761}
37933762
3794static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {3763void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
3795 assert(fn_table_entry->anal_state != FnAnalStateProbing);3764 assert(fn_table_entry->anal_state != FnAnalStateProbing);
3796 if (fn_table_entry->anal_state != FnAnalStateReady)3765 if (fn_table_entry->anal_state != FnAnalStateReady)
3797 return;3766 return;
...@@ -4022,7 +3991,8 @@ void semantic_analyze(CodeGen *g) {...@@ -4022,7 +3991,8 @@ void semantic_analyze(CodeGen *g) {
4022 for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) {3991 for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) {
4023 Tld *tld = g->resolve_queue.at(g->resolve_queue_index);3992 Tld *tld = g->resolve_queue.at(g->resolve_queue_index);
4024 bool pointer_only = false;3993 bool pointer_only = false;
4025 resolve_top_level_decl(g, tld, pointer_only, nullptr);3994 AstNode *source_node = nullptr;
3995 resolve_top_level_decl(g, tld, pointer_only, source_node);
4026 }3996 }
40273997
4028 for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) {3998 for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) {
...@@ -4114,7 +4084,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {...@@ -4114,7 +4084,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
4114 case TypeTableEntryIdInt:4084 case TypeTableEntryIdInt:
4115 case TypeTableEntryIdFloat:4085 case TypeTableEntryIdFloat:
4116 case TypeTableEntryIdPointer:4086 case TypeTableEntryIdPointer:
4117 case TypeTableEntryIdPureError:4087 case TypeTableEntryIdErrorSet:
4118 case TypeTableEntryIdFn:4088 case TypeTableEntryIdFn:
4119 case TypeTableEntryIdEnum:4089 case TypeTableEntryIdEnum:
4120 return false;4090 return false;
...@@ -4122,7 +4092,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {...@@ -4122,7 +4092,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
4122 case TypeTableEntryIdStruct:4092 case TypeTableEntryIdStruct:
4123 return type_has_bits(type_entry);4093 return type_has_bits(type_entry);
4124 case TypeTableEntryIdErrorUnion:4094 case TypeTableEntryIdErrorUnion:
4125 return type_has_bits(type_entry->data.error.child_type);4095 return type_has_bits(type_entry->data.error_union.payload_type);
4126 case TypeTableEntryIdMaybe:4096 case TypeTableEntryIdMaybe:
4127 return type_has_bits(type_entry->data.maybe.child_type) &&4097 return type_has_bits(type_entry->data.maybe.child_type) &&
4128 type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer &&4098 type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer &&
...@@ -4386,9 +4356,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {...@@ -4386,9 +4356,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
4386 case TypeTableEntryIdErrorUnion:4356 case TypeTableEntryIdErrorUnion:
4387 // TODO better hashing algorithm4357 // TODO better hashing algorithm
4388 return 3415065496;4358 return 3415065496;
4389 case TypeTableEntryIdPureError:4359 case TypeTableEntryIdErrorSet:
4390 // TODO better hashing algorithm4360 assert(const_val->data.x_err_set != nullptr);
4391 return 2630160122;4361 return const_val->data.x_err_set->value ^ 2630160122;
4392 case TypeTableEntryIdFn:4362 case TypeTableEntryIdFn:
4393 return 4133894920 ^ hash_ptr(const_val->data.x_fn.fn_entry);4363 return 4133894920 ^ hash_ptr(const_val->data.x_fn.fn_entry);
4394 case TypeTableEntryIdNamespace:4364 case TypeTableEntryIdNamespace:
...@@ -4515,7 +4485,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {...@@ -4515,7 +4485,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
4515 case TypeTableEntryIdMaybe:4485 case TypeTableEntryIdMaybe:
4516 case TypeTableEntryIdErrorUnion:4486 case TypeTableEntryIdErrorUnion:
4517 case TypeTableEntryIdEnum:4487 case TypeTableEntryIdEnum:
4518 case TypeTableEntryIdPureError:4488 case TypeTableEntryIdErrorSet:
4519 case TypeTableEntryIdFn:4489 case TypeTableEntryIdFn:
4520 case TypeTableEntryIdBool:4490 case TypeTableEntryIdBool:
4521 case TypeTableEntryIdInt:4491 case TypeTableEntryIdInt:
...@@ -4894,8 +4864,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {...@@ -4894,8 +4864,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
4894 return a->data.x_type == b->data.x_type;4864 return a->data.x_type == b->data.x_type;
4895 case TypeTableEntryIdVoid:4865 case TypeTableEntryIdVoid:
4896 return true;4866 return true;
4897 case TypeTableEntryIdPureError:4867 case TypeTableEntryIdErrorSet:
4898 return a->data.x_pure_err == b->data.x_pure_err;4868 return a->data.x_err_set->value == b->data.x_err_set->value;
4899 case TypeTableEntryIdFn:4869 case TypeTableEntryIdFn:
4900 return a->data.x_fn.fn_entry == b->data.x_fn.fn_entry;4870 return a->data.x_fn.fn_entry == b->data.x_fn.fn_entry;
4901 case TypeTableEntryIdBool:4871 case TypeTableEntryIdBool:
...@@ -5256,9 +5226,9 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {...@@ -5256,9 +5226,9 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
5256 buf_appendf(buf, "(union %s constant)", buf_ptr(&type_entry->name));5226 buf_appendf(buf, "(union %s constant)", buf_ptr(&type_entry->name));
5257 return;5227 return;
5258 }5228 }
5259 case TypeTableEntryIdPureError:5229 case TypeTableEntryIdErrorSet:
5260 {5230 {
5261 buf_appendf(buf, "(pure error constant)");5231 buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name));
5262 return;5232 return;
5263 }5233 }
5264 case TypeTableEntryIdArgTuple:5234 case TypeTableEntryIdArgTuple:
...@@ -5319,8 +5289,7 @@ uint32_t type_id_hash(TypeId x) {...@@ -5319,8 +5289,7 @@ uint32_t type_id_hash(TypeId x) {
5319 case TypeTableEntryIdUndefLit:5289 case TypeTableEntryIdUndefLit:
5320 case TypeTableEntryIdNullLit:5290 case TypeTableEntryIdNullLit:
5321 case TypeTableEntryIdMaybe:5291 case TypeTableEntryIdMaybe:
5322 case TypeTableEntryIdErrorUnion:5292 case TypeTableEntryIdErrorSet:
5323 case TypeTableEntryIdPureError:
5324 case TypeTableEntryIdEnum:5293 case TypeTableEntryIdEnum:
5325 case TypeTableEntryIdUnion:5294 case TypeTableEntryIdUnion:
5326 case TypeTableEntryIdFn:5295 case TypeTableEntryIdFn:
...@@ -5329,6 +5298,8 @@ uint32_t type_id_hash(TypeId x) {...@@ -5329,6 +5298,8 @@ uint32_t type_id_hash(TypeId x) {
5329 case TypeTableEntryIdBoundFn:5298 case TypeTableEntryIdBoundFn:
5330 case TypeTableEntryIdArgTuple:5299 case TypeTableEntryIdArgTuple:
5331 zig_unreachable();5300 zig_unreachable();
5301 case TypeTableEntryIdErrorUnion:
5302 return hash_ptr(x.data.error_union.err_set_type) ^ hash_ptr(x.data.error_union.payload_type);
5332 case TypeTableEntryIdPointer:5303 case TypeTableEntryIdPointer:
5333 return hash_ptr(x.data.pointer.child_type) +5304 return hash_ptr(x.data.pointer.child_type) +
5334 (x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) +5305 (x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) +
...@@ -5363,8 +5334,7 @@ bool type_id_eql(TypeId a, TypeId b) {...@@ -5363,8 +5334,7 @@ bool type_id_eql(TypeId a, TypeId b) {
5363 case TypeTableEntryIdUndefLit:5334 case TypeTableEntryIdUndefLit:
5364 case TypeTableEntryIdNullLit:5335 case TypeTableEntryIdNullLit:
5365 case TypeTableEntryIdMaybe:5336 case TypeTableEntryIdMaybe:
5366 case TypeTableEntryIdErrorUnion:5337 case TypeTableEntryIdErrorSet:
5367 case TypeTableEntryIdPureError:
5368 case TypeTableEntryIdEnum:5338 case TypeTableEntryIdEnum:
5369 case TypeTableEntryIdUnion:5339 case TypeTableEntryIdUnion:
5370 case TypeTableEntryIdFn:5340 case TypeTableEntryIdFn:
...@@ -5374,6 +5344,10 @@ bool type_id_eql(TypeId a, TypeId b) {...@@ -5374,6 +5344,10 @@ bool type_id_eql(TypeId a, TypeId b) {
5374 case TypeTableEntryIdArgTuple:5344 case TypeTableEntryIdArgTuple:
5375 case TypeTableEntryIdOpaque:5345 case TypeTableEntryIdOpaque:
5376 zig_unreachable();5346 zig_unreachable();
5347 case TypeTableEntryIdErrorUnion:
5348 return a.data.error_union.err_set_type == b.data.error_union.err_set_type &&
5349 a.data.error_union.payload_type == b.data.error_union.payload_type;
5350
5377 case TypeTableEntryIdPointer:5351 case TypeTableEntryIdPointer:
5378 return a.data.pointer.child_type == b.data.pointer.child_type &&5352 return a.data.pointer.child_type == b.data.pointer.child_type &&
5379 a.data.pointer.is_const == b.data.pointer.is_const &&5353 a.data.pointer.is_const == b.data.pointer.is_const &&
...@@ -5478,7 +5452,7 @@ static const TypeTableEntryId all_type_ids[] = {...@@ -5478,7 +5452,7 @@ static const TypeTableEntryId all_type_ids[] = {
5478 TypeTableEntryIdNullLit,5452 TypeTableEntryIdNullLit,
5479 TypeTableEntryIdMaybe,5453 TypeTableEntryIdMaybe,
5480 TypeTableEntryIdErrorUnion,5454 TypeTableEntryIdErrorUnion,
5481 TypeTableEntryIdPureError,5455 TypeTableEntryIdErrorSet,
5482 TypeTableEntryIdEnum,5456 TypeTableEntryIdEnum,
5483 TypeTableEntryIdUnion,5457 TypeTableEntryIdUnion,
5484 TypeTableEntryIdFn,5458 TypeTableEntryIdFn,
...@@ -5533,7 +5507,7 @@ size_t type_id_index(TypeTableEntryId id) {...@@ -5533,7 +5507,7 @@ size_t type_id_index(TypeTableEntryId id) {
5533 return 13;5507 return 13;
5534 case TypeTableEntryIdErrorUnion:5508 case TypeTableEntryIdErrorUnion:
5535 return 14;5509 return 14;
5536 case TypeTableEntryIdPureError:5510 case TypeTableEntryIdErrorSet:
5537 return 15;5511 return 15;
5538 case TypeTableEntryIdEnum:5512 case TypeTableEntryIdEnum:
5539 return 16;5513 return 16;
...@@ -5590,8 +5564,8 @@ const char *type_id_name(TypeTableEntryId id) {...@@ -5590,8 +5564,8 @@ const char *type_id_name(TypeTableEntryId id) {
5590 return "Nullable";5564 return "Nullable";
5591 case TypeTableEntryIdErrorUnion:5565 case TypeTableEntryIdErrorUnion:
5592 return "ErrorUnion";5566 return "ErrorUnion";
5593 case TypeTableEntryIdPureError:5567 case TypeTableEntryIdErrorSet:
5594 return "Error";5568 return "ErrorSet";
5595 case TypeTableEntryIdEnum:5569 case TypeTableEntryIdEnum:
5596 return "Enum";5570 return "Enum";
5597 case TypeTableEntryIdUnion:5571 case TypeTableEntryIdUnion:
...@@ -5640,17 +5614,6 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) {...@@ -5640,17 +5614,6 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) {
5640 return link_lib;5614 return link_lib;
5641}5615}
56425616
5643void add_link_lib_symbol(CodeGen *g, Buf *lib_name, Buf *symbol_name) {
5644 LinkLib *link_lib = add_link_lib(g, lib_name);
5645 for (size_t i = 0; i < link_lib->symbols.length; i += 1) {
5646 Buf *existing_symbol_name = link_lib->symbols.at(i);
5647 if (buf_eql_buf(existing_symbol_name, symbol_name)) {
5648 return;
5649 }
5650 }
5651 link_lib->symbols.append(symbol_name);
5652}
5653
5654uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) {5617uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) {
5655 type_ensure_zero_bits_known(g, type_entry);5618 type_ensure_zero_bits_known(g, type_entry);
5656 if (type_entry->zero_bits) return 0;5619 if (type_entry->zero_bits) return 0;
...@@ -5696,3 +5659,8 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {...@@ -5696,3 +5659,8 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
5696 return var_value;5659 return var_value;
5697}5660}
56985661
5662bool type_is_global_error_set(TypeTableEntry *err_set_type) {
5663 assert(err_set_type->id == TypeTableEntryIdErrorSet);
5664 assert(err_set_type->data.error_set.infer_fn == nullptr);
5665 return err_set_type->data.error_set.err_count == UINT32_MAX;
5666}
src/analyze.hpp+4-4
...@@ -30,7 +30,7 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type);...@@ -30,7 +30,7 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type);
30TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,30TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,
31 AstNode *decl_node, const char *name, ContainerLayout layout);31 AstNode *decl_node, const char *name, ContainerLayout layout);
32TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);32TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
33TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type);33TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, TypeTableEntry *payload_type);
34TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry);34TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry);
35TypeTableEntry *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *name);35TypeTableEntry *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *name);
36TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],36TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
...@@ -46,8 +46,6 @@ bool type_has_bits(TypeTableEntry *type_entry);...@@ -46,8 +46,6 @@ bool type_has_bits(TypeTableEntry *type_entry);
46ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code);46ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code);
4747
4848
49// TODO move these over, these used to be static
50bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type);
51VariableTableEntry *find_variable(CodeGen *g, Scope *orig_context, Buf *name);49VariableTableEntry *find_variable(CodeGen *g, Scope *orig_context, Buf *name);
52Tld *find_decl(CodeGen *g, Scope *scope, Buf *name);50Tld *find_decl(CodeGen *g, Scope *scope, Buf *name);
53void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node);51void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node);
...@@ -58,6 +56,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt...@@ -58,6 +56,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
58TypeTableEntry *container_ref_type(TypeTableEntry *type_entry);56TypeTableEntry *container_ref_type(TypeTableEntry *type_entry);
59bool type_is_complete(TypeTableEntry *type_entry);57bool type_is_complete(TypeTableEntry *type_entry);
60bool type_is_invalid(TypeTableEntry *type_entry);58bool type_is_invalid(TypeTableEntry *type_entry);
59bool type_is_global_error_set(TypeTableEntry *err_set_type);
61bool type_has_zero_bits_known(TypeTableEntry *type_entry);60bool type_has_zero_bits_known(TypeTableEntry *type_entry);
62void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry);61void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry);
63ScopeDecls *get_container_scope(TypeTableEntry *type_entry);62ScopeDecls *get_container_scope(TypeTableEntry *type_entry);
...@@ -176,7 +175,6 @@ bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry);...@@ -176,7 +175,6 @@ bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry);
176LinkLib *create_link_lib(Buf *name);175LinkLib *create_link_lib(Buf *name);
177bool calling_convention_does_first_arg_return(CallingConvention cc);176bool calling_convention_does_first_arg_return(CallingConvention cc);
178LinkLib *add_link_lib(CodeGen *codegen, Buf *lib);177LinkLib *add_link_lib(CodeGen *codegen, Buf *lib);
179void add_link_lib_symbol(CodeGen *g, Buf *lib_name, Buf *symbol_name);
180178
181uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry);179uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry);
182TypeTableEntry *get_align_amt_type(CodeGen *g);180TypeTableEntry *get_align_amt_type(CodeGen *g);
...@@ -188,6 +186,8 @@ void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, G...@@ -188,6 +186,8 @@ void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, G
188186
189ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);187ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
190TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g);188TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g);
189void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);
191190
191TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry);
192192
193#endif193#endif
src/ast_render.cpp+26-7
...@@ -49,11 +49,12 @@ static const char *bin_op_str(BinOpType bin_op) {...@@ -49,11 +49,12 @@ static const char *bin_op_str(BinOpType bin_op) {
49 case BinOpTypeAssignBitAnd: return "&=";49 case BinOpTypeAssignBitAnd: return "&=";
50 case BinOpTypeAssignBitXor: return "^=";50 case BinOpTypeAssignBitXor: return "^=";
51 case BinOpTypeAssignBitOr: return "|=";51 case BinOpTypeAssignBitOr: return "|=";
52 case BinOpTypeAssignBoolAnd: return "&&=";52 case BinOpTypeAssignMergeErrorSets: return "||=";
53 case BinOpTypeAssignBoolOr: return "||=";
54 case BinOpTypeUnwrapMaybe: return "??";53 case BinOpTypeUnwrapMaybe: return "??";
55 case BinOpTypeArrayCat: return "++";54 case BinOpTypeArrayCat: return "++";
56 case BinOpTypeArrayMult: return "**";55 case BinOpTypeArrayMult: return "**";
56 case BinOpTypeErrorUnion: return "!";
57 case BinOpTypeMergeErrorSets: return "||";
57 }58 }
58 zig_unreachable();59 zig_unreachable();
59}60}
...@@ -67,7 +68,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) {...@@ -67,7 +68,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
67 case PrefixOpBinNot: return "~";68 case PrefixOpBinNot: return "~";
68 case PrefixOpDereference: return "*";69 case PrefixOpDereference: return "*";
69 case PrefixOpMaybe: return "?";70 case PrefixOpMaybe: return "?";
70 case PrefixOpError: return "%";
71 case PrefixOpUnwrapMaybe: return "??";71 case PrefixOpUnwrapMaybe: return "??";
72 }72 }
73 zig_unreachable();73 zig_unreachable();
...@@ -174,8 +174,6 @@ static const char *node_type_str(NodeType node_type) {...@@ -174,8 +174,6 @@ static const char *node_type_str(NodeType node_type) {
174 return "Defer";174 return "Defer";
175 case NodeTypeVariableDeclaration:175 case NodeTypeVariableDeclaration:
176 return "VariableDeclaration";176 return "VariableDeclaration";
177 case NodeTypeErrorValueDecl:
178 return "ErrorValueDecl";
179 case NodeTypeTestDecl:177 case NodeTypeTestDecl:
180 return "TestDecl";178 return "TestDecl";
181 case NodeTypeIntLiteral:179 case NodeTypeIntLiteral:
...@@ -244,6 +242,8 @@ static const char *node_type_str(NodeType node_type) {...@@ -244,6 +242,8 @@ static const char *node_type_str(NodeType node_type) {
244 return "IfErrorExpr";242 return "IfErrorExpr";
245 case NodeTypeTestExpr:243 case NodeTypeTestExpr:
246 return "TestExpr";244 return "TestExpr";
245 case NodeTypeErrorSetDecl:
246 return "ErrorSetDecl";
247 }247 }
248 zig_unreachable();248 zig_unreachable();
249}249}
...@@ -396,7 +396,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -396,7 +396,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
396396
397 if (child->type == NodeTypeUse ||397 if (child->type == NodeTypeUse ||
398 child->type == NodeTypeVariableDeclaration ||398 child->type == NodeTypeVariableDeclaration ||
399 child->type == NodeTypeErrorValueDecl ||
400 child->type == NodeTypeFnProto)399 child->type == NodeTypeFnProto)
401 {400 {
402 fprintf(ar->f, ";");401 fprintf(ar->f, ";");
...@@ -452,6 +451,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -452,6 +451,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
452 AstNode *return_type_node = node->data.fn_proto.return_type;451 AstNode *return_type_node = node->data.fn_proto.return_type;
453 assert(return_type_node != nullptr);452 assert(return_type_node != nullptr);
454 fprintf(ar->f, " ");453 fprintf(ar->f, " ");
454 if (node->data.fn_proto.auto_err_set) {
455 fprintf(ar->f, "!");
456 }
455 render_node_grouped(ar, return_type_node);457 render_node_grouped(ar, return_type_node);
456 break;458 break;
457 }459 }
...@@ -1017,9 +1019,26 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -1017,9 +1019,26 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
1017 render_node_ungrouped(ar, node->data.unwrap_err_expr.op2);1019 render_node_ungrouped(ar, node->data.unwrap_err_expr.op2);
1018 break;1020 break;
1019 }1021 }
1022 case NodeTypeErrorSetDecl:
1023 {
1024 fprintf(ar->f, "error {\n");
1025 ar->indent += ar->indent_size;
1026
1027 for (size_t i = 0; i < node->data.err_set_decl.decls.length; i += 1) {
1028 AstNode *field_node = node->data.err_set_decl.decls.at(i);
1029 assert(field_node->type == NodeTypeSymbol);
1030 print_indent(ar);
1031 print_symbol(ar, field_node->data.symbol_expr.symbol);
1032 fprintf(ar->f, ",\n");
1033 }
1034
1035 ar->indent -= ar->indent_size;
1036 print_indent(ar);
1037 fprintf(ar->f, "}");
1038 break;
1039 }
1020 case NodeTypeFnDecl:1040 case NodeTypeFnDecl:
1021 case NodeTypeParamDecl:1041 case NodeTypeParamDecl:
1022 case NodeTypeErrorValueDecl:
1023 case NodeTypeTestDecl:1042 case NodeTypeTestDecl:
1024 case NodeTypeStructField:1043 case NodeTypeStructField:
1025 case NodeTypeUse:1044 case NodeTypeUse:
src/codegen.cpp+156-76
...@@ -92,9 +92,6 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out...@@ -92,9 +92,6 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
92 g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib);92 g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib);
93 buf_resize(&g->global_asm, 0);93 buf_resize(&g->global_asm, 0);
9494
95 // reserve index 0 to indicate no error
96 g->error_decls.append(nullptr);
97
98 if (root_src_path) {95 if (root_src_path) {
99 Buf *src_basename = buf_alloc();96 Buf *src_basename = buf_alloc();
100 Buf *src_dir = buf_alloc();97 Buf *src_dir = buf_alloc();
...@@ -256,6 +253,10 @@ LinkLib *codegen_add_link_lib(CodeGen *g, Buf *name) {...@@ -256,6 +253,10 @@ LinkLib *codegen_add_link_lib(CodeGen *g, Buf *name) {
256 return add_link_lib(g, name);253 return add_link_lib(g, name);
257}254}
258255
256void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib) {
257 codegen->forbidden_libs.append(lib);
258}
259
259void codegen_add_framework(CodeGen *g, const char *framework) {260void codegen_add_framework(CodeGen *g, const char *framework) {
260 g->darwin_frameworks.append(buf_create_from_str(framework));261 g->darwin_frameworks.append(buf_create_from_str(framework));
261}262}
...@@ -410,7 +411,7 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e...@@ -410,7 +411,7 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e
410 }411 }
411 TypeTableEntry *fn_type = fn_table_entry->type_entry;412 TypeTableEntry *fn_type = fn_table_entry->type_entry;
412 TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;413 TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
413 if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdPureError) {414 if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdErrorSet) {
414 return UINT32_MAX;415 return UINT32_MAX;
415 }416 }
416 bool first_arg_ret = type_has_bits(return_type) && handle_is_ptr(return_type);417 bool first_arg_ret = type_has_bits(return_type) && handle_is_ptr(return_type);
...@@ -1442,7 +1443,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns...@@ -1442,7 +1443,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
1442 is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError;1443 is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError;
1443 // TODO: emit a branch to check if the return value is an error1444 // TODO: emit a branch to check if the return value is an error
1444 }1445 }
1445 } else if (return_type->id == TypeTableEntryIdPureError) {1446 } else if (return_type->id == TypeTableEntryIdErrorSet) {
1446 is_err_return = true;1447 is_err_return = true;
1447 }1448 }
1448 if (is_err_return) {1449 if (is_err_return) {
...@@ -1789,7 +1790,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -1789,7 +1790,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
17891790
1790 assert(op1->value.type == op2->value.type || op_id == IrBinOpBitShiftLeftLossy ||1791 assert(op1->value.type == op2->value.type || op_id == IrBinOpBitShiftLeftLossy ||
1791 op_id == IrBinOpBitShiftLeftExact || op_id == IrBinOpBitShiftRightLossy ||1792 op_id == IrBinOpBitShiftLeftExact || op_id == IrBinOpBitShiftRightLossy ||
1792 op_id == IrBinOpBitShiftRightExact);1793 op_id == IrBinOpBitShiftRightExact ||
1794 (op1->value.type->id == TypeTableEntryIdErrorSet && op2->value.type->id == TypeTableEntryIdErrorSet));
1793 TypeTableEntry *type_entry = op1->value.type;1795 TypeTableEntry *type_entry = op1->value.type;
17941796
1795 bool want_runtime_safety = bin_op_instruction->safety_check_on &&1797 bool want_runtime_safety = bin_op_instruction->safety_check_on &&
...@@ -1802,6 +1804,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -1802,6 +1804,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
1802 case IrBinOpArrayCat:1804 case IrBinOpArrayCat:
1803 case IrBinOpArrayMult:1805 case IrBinOpArrayMult:
1804 case IrBinOpRemUnspecified:1806 case IrBinOpRemUnspecified:
1807 case IrBinOpMergeErrorSets:
1805 zig_unreachable();1808 zig_unreachable();
1806 case IrBinOpBoolOr:1809 case IrBinOpBoolOr:
1807 return LLVMBuildOr(g->builder, op1_value, op2_value, "");1810 return LLVMBuildOr(g->builder, op1_value, op2_value, "");
...@@ -1823,7 +1826,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -1823,7 +1826,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
1823 } else if (type_entry->id == TypeTableEntryIdEnum) {1826 } else if (type_entry->id == TypeTableEntryIdEnum) {
1824 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);1827 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
1825 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");1828 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
1826 } else if (type_entry->id == TypeTableEntryIdPureError ||1829 } else if (type_entry->id == TypeTableEntryIdErrorSet ||
1827 type_entry->id == TypeTableEntryIdPointer ||1830 type_entry->id == TypeTableEntryIdPointer ||
1828 type_entry->id == TypeTableEntryIdBool)1831 type_entry->id == TypeTableEntryIdBool)
1829 {1832 {
...@@ -1955,6 +1958,54 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -1955,6 +1958,54 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
1955 zig_unreachable();1958 zig_unreachable();
1956}1959}
19571960
1961static void add_error_range_check(CodeGen *g, TypeTableEntry *err_set_type, TypeTableEntry *int_type, LLVMValueRef target_val) {
1962 assert(err_set_type->id == TypeTableEntryIdErrorSet);
1963
1964 if (type_is_global_error_set(err_set_type)) {
1965 LLVMValueRef zero = LLVMConstNull(int_type->type_ref);
1966 LLVMValueRef neq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target_val, zero, "");
1967 LLVMValueRef ok_bit;
1968
1969 BigInt biggest_possible_err_val = {0};
1970 eval_min_max_value_int(g, int_type, &biggest_possible_err_val, true);
1971
1972 if (bigint_fits_in_bits(&biggest_possible_err_val, 64, false) &&
1973 bigint_as_unsigned(&biggest_possible_err_val) < g->errors_by_index.length)
1974 {
1975 ok_bit = neq_zero_bit;
1976 } else {
1977 LLVMValueRef error_value_count = LLVMConstInt(int_type->type_ref, g->errors_by_index.length, false);
1978 LLVMValueRef in_bounds_bit = LLVMBuildICmp(g->builder, LLVMIntULT, target_val, error_value_count, "");
1979 ok_bit = LLVMBuildAnd(g->builder, neq_zero_bit, in_bounds_bit, "");
1980 }
1981
1982 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrOk");
1983 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrFail");
1984
1985 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
1986
1987 LLVMPositionBuilderAtEnd(g->builder, fail_block);
1988 gen_safety_crash(g, PanicMsgIdInvalidErrorCode);
1989
1990 LLVMPositionBuilderAtEnd(g->builder, ok_block);
1991 } else {
1992 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrOk");
1993 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrFail");
1994
1995 uint32_t err_count = err_set_type->data.error_set.err_count;
1996 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, target_val, fail_block, err_count);
1997 for (uint32_t i = 0; i < err_count; i += 1) {
1998 LLVMValueRef case_value = LLVMConstInt(g->err_tag_type->type_ref, err_set_type->data.error_set.errors[i]->value, false);
1999 LLVMAddCase(switch_instr, case_value, ok_block);
2000 }
2001
2002 LLVMPositionBuilderAtEnd(g->builder, fail_block);
2003 gen_safety_crash(g, PanicMsgIdInvalidErrorCode);
2004
2005 LLVMPositionBuilderAtEnd(g->builder, ok_block);
2006 }
2007}
2008
1958static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,2009static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
1959 IrInstructionCast *cast_instruction)2010 IrInstructionCast *cast_instruction)
1960{2011{
...@@ -2078,6 +2129,11 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,...@@ -2078,6 +2129,11 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
2078 assert(wanted_type->id == TypeTableEntryIdInt);2129 assert(wanted_type->id == TypeTableEntryIdInt);
2079 assert(actual_type->id == TypeTableEntryIdBool);2130 assert(actual_type->id == TypeTableEntryIdBool);
2080 return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");2131 return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
2132 case CastOpErrSet:
2133 if (ir_want_runtime_safety(g, &cast_instruction->base)) {
2134 add_error_range_check(g, wanted_type, g->err_tag_type, expr_val);
2135 }
2136 return expr_val;
2081 }2137 }
2082 zig_unreachable();2138 zig_unreachable();
2083}2139}
...@@ -2139,7 +2195,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,...@@ -2139,7 +2195,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,
21392195
2140static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) {2196static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) {
2141 TypeTableEntry *wanted_type = instruction->base.value.type;2197 TypeTableEntry *wanted_type = instruction->base.value.type;
2142 assert(wanted_type->id == TypeTableEntryIdPureError);2198 assert(wanted_type->id == TypeTableEntryIdErrorSet);
21432199
2144 TypeTableEntry *actual_type = instruction->target->value.type;2200 TypeTableEntry *actual_type = instruction->target->value.type;
2145 assert(actual_type->id == TypeTableEntryIdInt);2201 assert(actual_type->id == TypeTableEntryIdInt);
...@@ -2148,32 +2204,7 @@ static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, I...@@ -2148,32 +2204,7 @@ static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, I
2148 LLVMValueRef target_val = ir_llvm_value(g, instruction->target);2204 LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
21492205
2150 if (ir_want_runtime_safety(g, &instruction->base)) {2206 if (ir_want_runtime_safety(g, &instruction->base)) {
2151 LLVMValueRef zero = LLVMConstNull(actual_type->type_ref);2207 add_error_range_check(g, wanted_type, actual_type, target_val);
2152 LLVMValueRef neq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target_val, zero, "");
2153 LLVMValueRef ok_bit;
2154
2155 BigInt biggest_possible_err_val = {0};
2156 eval_min_max_value_int(g, actual_type, &biggest_possible_err_val, true);
2157
2158 if (bigint_fits_in_bits(&biggest_possible_err_val, 64, false) &&
2159 bigint_as_unsigned(&biggest_possible_err_val) < g->error_decls.length)
2160 {
2161 ok_bit = neq_zero_bit;
2162 } else {
2163 LLVMValueRef error_value_count = LLVMConstInt(actual_type->type_ref, g->error_decls.length, false);
2164 LLVMValueRef in_bounds_bit = LLVMBuildICmp(g->builder, LLVMIntULT, target_val, error_value_count, "");
2165 ok_bit = LLVMBuildAnd(g->builder, neq_zero_bit, in_bounds_bit, "");
2166 }
2167
2168 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrOk");
2169 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrFail");
2170
2171 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
2172
2173 LLVMPositionBuilderAtEnd(g->builder, fail_block);
2174 gen_safety_crash(g, PanicMsgIdInvalidErrorCode);
2175
2176 LLVMPositionBuilderAtEnd(g->builder, ok_block);
2177 }2208 }
21782209
2179 return gen_widen_or_shorten(g, false, actual_type, g->err_tag_type, target_val);2210 return gen_widen_or_shorten(g, false, actual_type, g->err_tag_type, target_val);
...@@ -2187,15 +2218,18 @@ static LLVMValueRef ir_render_err_to_int(CodeGen *g, IrExecutable *executable, I...@@ -2187,15 +2218,18 @@ static LLVMValueRef ir_render_err_to_int(CodeGen *g, IrExecutable *executable, I
2187 TypeTableEntry *actual_type = instruction->target->value.type;2218 TypeTableEntry *actual_type = instruction->target->value.type;
2188 LLVMValueRef target_val = ir_llvm_value(g, instruction->target);2219 LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
21892220
2190 if (actual_type->id == TypeTableEntryIdPureError) {2221 if (actual_type->id == TypeTableEntryIdErrorSet) {
2191 return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),2222 return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
2192 g->err_tag_type, wanted_type, target_val);2223 g->err_tag_type, wanted_type, target_val);
2193 } else if (actual_type->id == TypeTableEntryIdErrorUnion) {2224 } else if (actual_type->id == TypeTableEntryIdErrorUnion) {
2194 if (!type_has_bits(actual_type->data.error.child_type)) {2225 // this should have been a compile time constant
2226 assert(type_has_bits(actual_type->data.error_union.err_set_type));
2227
2228 if (!type_has_bits(actual_type->data.error_union.payload_type)) {
2195 return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),2229 return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
2196 g->err_tag_type, wanted_type, target_val);2230 g->err_tag_type, wanted_type, target_val);
2197 } else {2231 } else {
2198 zig_panic("TODO");2232 zig_panic("TODO err to int when error union payload type not void");
2199 }2233 }
2200 } else {2234 } else {
2201 zig_unreachable();2235 zig_unreachable();
...@@ -2235,7 +2269,6 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst...@@ -2235,7 +2269,6 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
22352269
2236 switch (op_id) {2270 switch (op_id) {
2237 case IrUnOpInvalid:2271 case IrUnOpInvalid:
2238 case IrUnOpError:
2239 case IrUnOpMaybe:2272 case IrUnOpMaybe:
2240 case IrUnOpDereference:2273 case IrUnOpDereference:
2241 zig_unreachable();2274 zig_unreachable();
...@@ -2489,7 +2522,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -2489,7 +2522,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
2489 TypeTableEntry *src_return_type = fn_type_id->return_type;2522 TypeTableEntry *src_return_type = fn_type_id->return_type;
2490 bool ret_has_bits = type_has_bits(src_return_type);2523 bool ret_has_bits = type_has_bits(src_return_type);
2491 bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type);2524 bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type);
2492 bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdPureError);2525 bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdErrorSet);
2493 size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0);2526 size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0);
2494 bool is_var_args = fn_type_id->is_var_args;2527 bool is_var_args = fn_type_id->is_var_args;
2495 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);2528 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
...@@ -2907,7 +2940,7 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstru...@@ -2907,7 +2940,7 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstru
2907static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrInstructionErrName *instruction) {2940static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrInstructionErrName *instruction) {
2908 assert(g->generate_error_name_table);2941 assert(g->generate_error_name_table);
29092942
2910 if (g->error_decls.length == 1) {2943 if (g->errors_by_index.length == 1) {
2911 LLVMBuildUnreachable(g->builder);2944 LLVMBuildUnreachable(g->builder);
2912 return nullptr;2945 return nullptr;
2913 }2946 }
...@@ -2915,7 +2948,7 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI...@@ -2915,7 +2948,7 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI
2915 LLVMValueRef err_val = ir_llvm_value(g, instruction->value);2948 LLVMValueRef err_val = ir_llvm_value(g, instruction->value);
2916 if (ir_want_runtime_safety(g, &instruction->base)) {2949 if (ir_want_runtime_safety(g, &instruction->base)) {
2917 LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(err_val));2950 LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(err_val));
2918 LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(err_val), g->error_decls.length, false);2951 LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(err_val), g->errors_by_index.length, false);
2919 add_bounds_check(g, err_val, LLVMIntNE, zero, LLVMIntULT, end_val);2952 add_bounds_check(g, err_val, LLVMIntNE, zero, LLVMIntULT, end_val);
2920 }2953 }
29212954
...@@ -3393,11 +3426,11 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable,...@@ -3393,11 +3426,11 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable,
33933426
3394static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) {3427static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) {
3395 TypeTableEntry *err_union_type = instruction->value->value.type;3428 TypeTableEntry *err_union_type = instruction->value->value.type;
3396 TypeTableEntry *child_type = err_union_type->data.error.child_type;3429 TypeTableEntry *payload_type = err_union_type->data.error_union.payload_type;
3397 LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->value);3430 LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->value);
33983431
3399 LLVMValueRef err_val;3432 LLVMValueRef err_val;
3400 if (type_has_bits(child_type)) {3433 if (type_has_bits(payload_type)) {
3401 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");3434 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
3402 err_val = gen_load_untyped(g, err_val_ptr, 0, false, "");3435 err_val = gen_load_untyped(g, err_val_ptr, 0, false, "");
3403 } else {3436 } else {
...@@ -3412,11 +3445,11 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab...@@ -3412,11 +3445,11 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab
3412 TypeTableEntry *ptr_type = instruction->value->value.type;3445 TypeTableEntry *ptr_type = instruction->value->value.type;
3413 assert(ptr_type->id == TypeTableEntryIdPointer);3446 assert(ptr_type->id == TypeTableEntryIdPointer);
3414 TypeTableEntry *err_union_type = ptr_type->data.pointer.child_type;3447 TypeTableEntry *err_union_type = ptr_type->data.pointer.child_type;
3415 TypeTableEntry *child_type = err_union_type->data.error.child_type;3448 TypeTableEntry *payload_type = err_union_type->data.error_union.payload_type;
3416 LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);3449 LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
3417 LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);3450 LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
34183451
3419 if (type_has_bits(child_type)) {3452 if (type_has_bits(payload_type)) {
3420 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");3453 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
3421 return gen_load_untyped(g, err_val_ptr, 0, false, "");3454 return gen_load_untyped(g, err_val_ptr, 0, false, "");
3422 } else {3455 } else {
...@@ -3428,13 +3461,17 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu...@@ -3428,13 +3461,17 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
3428 TypeTableEntry *ptr_type = instruction->value->value.type;3461 TypeTableEntry *ptr_type = instruction->value->value.type;
3429 assert(ptr_type->id == TypeTableEntryIdPointer);3462 assert(ptr_type->id == TypeTableEntryIdPointer);
3430 TypeTableEntry *err_union_type = ptr_type->data.pointer.child_type;3463 TypeTableEntry *err_union_type = ptr_type->data.pointer.child_type;
3431 TypeTableEntry *child_type = err_union_type->data.error.child_type;3464 TypeTableEntry *payload_type = err_union_type->data.error_union.payload_type;
3432 LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);3465 LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
3433 LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);3466 LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
34343467
3435 if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->error_decls.length > 1) {3468 if (!type_has_bits(err_union_type->data.error_union.err_set_type)) {
3469 return err_union_handle;
3470 }
3471
3472 if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) {
3436 LLVMValueRef err_val;3473 LLVMValueRef err_val;
3437 if (type_has_bits(child_type)) {3474 if (type_has_bits(payload_type)) {
3438 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");3475 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
3439 err_val = gen_load_untyped(g, err_val_ptr, 0, false, "");3476 err_val = gen_load_untyped(g, err_val_ptr, 0, false, "");
3440 } else {3477 } else {
...@@ -3452,7 +3489,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu...@@ -3452,7 +3489,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
3452 LLVMPositionBuilderAtEnd(g->builder, ok_block);3489 LLVMPositionBuilderAtEnd(g->builder, ok_block);
3453 }3490 }
34543491
3455 if (type_has_bits(child_type)) {3492 if (type_has_bits(payload_type)) {
3456 return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, "");3493 return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, "");
3457 } else {3494 } else {
3458 return nullptr;3495 return nullptr;
...@@ -3493,10 +3530,12 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable...@@ -3493,10 +3530,12 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable
34933530
3494 assert(wanted_type->id == TypeTableEntryIdErrorUnion);3531 assert(wanted_type->id == TypeTableEntryIdErrorUnion);
34953532
3496 TypeTableEntry *child_type = wanted_type->data.error.child_type;3533 TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type;
3534 TypeTableEntry *err_set_type = wanted_type->data.error_union.err_set_type;
3535
3497 LLVMValueRef err_val = ir_llvm_value(g, instruction->value);3536 LLVMValueRef err_val = ir_llvm_value(g, instruction->value);
34983537
3499 if (!type_has_bits(child_type))3538 if (!type_has_bits(payload_type) || !type_has_bits(err_set_type))
3500 return err_val;3539 return err_val;
35013540
3502 assert(instruction->tmp_ptr);3541 assert(instruction->tmp_ptr);
...@@ -3512,11 +3551,16 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa...@@ -3512,11 +3551,16 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
35123551
3513 assert(wanted_type->id == TypeTableEntryIdErrorUnion);3552 assert(wanted_type->id == TypeTableEntryIdErrorUnion);
35143553
3515 TypeTableEntry *child_type = wanted_type->data.error.child_type;3554 TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type;
3555 TypeTableEntry *err_set_type = wanted_type->data.error_union.err_set_type;
3556
3557 if (!type_has_bits(err_set_type)) {
3558 return ir_llvm_value(g, instruction->value);
3559 }
35163560
3517 LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref);3561 LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref);
35183562
3519 if (!type_has_bits(child_type))3563 if (!type_has_bits(payload_type))
3520 return ok_err_val;3564 return ok_err_val;
35213565
3522 assert(instruction->tmp_ptr);3566 assert(instruction->tmp_ptr);
...@@ -3527,7 +3571,7 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa...@@ -3527,7 +3571,7 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
3527 gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false);3571 gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false);
35283572
3529 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");3573 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
3530 gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, child_type, false), payload_val);3574 gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, payload_type, false), payload_val);
35313575
3532 return instruction->tmp_ptr;3576 return instruction->tmp_ptr;
3533}3577}
...@@ -3700,6 +3744,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -3700,6 +3744,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
3700 case IrInstructionIdArgType:3744 case IrInstructionIdArgType:
3701 case IrInstructionIdTagType:3745 case IrInstructionIdTagType:
3702 case IrInstructionIdExport:3746 case IrInstructionIdExport:
3747 case IrInstructionIdErrorUnion:
3703 zig_unreachable();3748 zig_unreachable();
3704 case IrInstructionIdReturn:3749 case IrInstructionIdReturn:
3705 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);3750 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
...@@ -3933,7 +3978,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con...@@ -3933,7 +3978,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
3933 case TypeTableEntryIdUndefLit:3978 case TypeTableEntryIdUndefLit:
3934 case TypeTableEntryIdNullLit:3979 case TypeTableEntryIdNullLit:
3935 case TypeTableEntryIdErrorUnion:3980 case TypeTableEntryIdErrorUnion:
3936 case TypeTableEntryIdPureError:3981 case TypeTableEntryIdErrorSet:
3937 case TypeTableEntryIdNamespace:3982 case TypeTableEntryIdNamespace:
3938 case TypeTableEntryIdBlock:3983 case TypeTableEntryIdBlock:
3939 case TypeTableEntryIdBoundFn:3984 case TypeTableEntryIdBoundFn:
...@@ -4026,10 +4071,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {...@@ -4026,10 +4071,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
4026 switch (type_entry->id) {4071 switch (type_entry->id) {
4027 case TypeTableEntryIdInt:4072 case TypeTableEntryIdInt:
4028 return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint);4073 return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint);
4029 case TypeTableEntryIdPureError:4074 case TypeTableEntryIdErrorSet:
4030 assert(const_val->data.x_pure_err);4075 assert(const_val->data.x_err_set != nullptr);
4031 return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref,4076 return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref,
4032 const_val->data.x_pure_err->value, false);4077 const_val->data.x_err_set->value, false);
4033 case TypeTableEntryIdFloat:4078 case TypeTableEntryIdFloat:
4034 switch (type_entry->data.floating.bit_count) {4079 switch (type_entry->data.floating.bit_count) {
4035 case 32:4080 case 32:
...@@ -4330,17 +4375,22 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {...@@ -4330,17 +4375,22 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
4330 }4375 }
4331 case TypeTableEntryIdErrorUnion:4376 case TypeTableEntryIdErrorUnion:
4332 {4377 {
4333 TypeTableEntry *child_type = type_entry->data.error.child_type;4378 TypeTableEntry *payload_type = type_entry->data.error_union.payload_type;
4334 if (!type_has_bits(child_type)) {4379 TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type;
4380 if (!type_has_bits(payload_type)) {
4381 assert(type_has_bits(err_set_type));
4335 uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0;4382 uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0;
4336 return LLVMConstInt(g->err_tag_type->type_ref, value, false);4383 return LLVMConstInt(g->err_tag_type->type_ref, value, false);
4384 } else if (!type_has_bits(err_set_type)) {
4385 assert(type_has_bits(payload_type));
4386 return gen_const_val(g, const_val->data.x_err_union.payload);
4337 } else {4387 } else {
4338 LLVMValueRef err_tag_value;4388 LLVMValueRef err_tag_value;
4339 LLVMValueRef err_payload_value;4389 LLVMValueRef err_payload_value;
4340 bool make_unnamed_struct;4390 bool make_unnamed_struct;
4341 if (const_val->data.x_err_union.err) {4391 if (const_val->data.x_err_union.err) {
4342 err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false);4392 err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false);
4343 err_payload_value = LLVMConstNull(child_type->type_ref);4393 err_payload_value = LLVMConstNull(payload_type->type_ref);
4344 make_unnamed_struct = false;4394 make_unnamed_struct = false;
4345 } else {4395 } else {
4346 err_tag_value = LLVMConstNull(g->err_tag_type->type_ref);4396 err_tag_value = LLVMConstNull(g->err_tag_type->type_ref);
...@@ -4410,21 +4460,20 @@ static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const...@@ -4410,21 +4460,20 @@ static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const
4410}4460}
44114461
4412static void generate_error_name_table(CodeGen *g) {4462static void generate_error_name_table(CodeGen *g) {
4413 if (g->err_name_table != nullptr || !g->generate_error_name_table || g->error_decls.length == 1) {4463 if (g->err_name_table != nullptr || !g->generate_error_name_table || g->errors_by_index.length == 1) {
4414 return;4464 return;
4415 }4465 }
44164466
4417 assert(g->error_decls.length > 0);4467 assert(g->errors_by_index.length > 0);
44184468
4419 TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);4469 TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
4420 TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);4470 TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
44214471
4422 LLVMValueRef *values = allocate<LLVMValueRef>(g->error_decls.length);4472 LLVMValueRef *values = allocate<LLVMValueRef>(g->errors_by_index.length);
4423 values[0] = LLVMGetUndef(str_type->type_ref);4473 values[0] = LLVMGetUndef(str_type->type_ref);
4424 for (size_t i = 1; i < g->error_decls.length; i += 1) {4474 for (size_t i = 1; i < g->errors_by_index.length; i += 1) {
4425 AstNode *error_decl_node = g->error_decls.at(i);4475 ErrorTableEntry *err_entry = g->errors_by_index.at(i);
4426 assert(error_decl_node->type == NodeTypeErrorValueDecl);4476 Buf *name = &err_entry->name;
4427 Buf *name = error_decl_node->data.error_value_decl.name;
44284477
4429 g->largest_err_name_len = max(g->largest_err_name_len, buf_len(name));4478 g->largest_err_name_len = max(g->largest_err_name_len, buf_len(name));
44304479
...@@ -4443,7 +4492,7 @@ static void generate_error_name_table(CodeGen *g) {...@@ -4443,7 +4492,7 @@ static void generate_error_name_table(CodeGen *g) {
4443 values[i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2);4492 values[i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2);
4444 }4493 }
44454494
4446 LLVMValueRef err_name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)g->error_decls.length);4495 LLVMValueRef err_name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)g->errors_by_index.length);
44474496
4448 g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init),4497 g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init),
4449 buf_ptr(get_mangled_name(g, buf_create_from_str("__zig_err_name_table"), false)));4498 buf_ptr(get_mangled_name(g, buf_create_from_str("__zig_err_name_table"), false)));
...@@ -4575,6 +4624,28 @@ static void do_code_gen(CodeGen *g) {...@@ -4575,6 +4624,28 @@ static void do_code_gen(CodeGen *g) {
45754624
4576 codegen_add_time_event(g, "Code Generation");4625 codegen_add_time_event(g, "Code Generation");
45774626
4627 {
4628 // create debug type for error sets
4629 assert(g->err_enumerators.length == g->errors_by_index.length);
4630 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, g->err_tag_type->type_ref);
4631 uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, g->err_tag_type->type_ref);
4632 ZigLLVMDIFile *err_set_di_file = nullptr;
4633 ZigLLVMDIType *err_set_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
4634 ZigLLVMCompileUnitToScope(g->compile_unit), buf_ptr(&g->builtin_types.entry_global_error_set->name),
4635 err_set_di_file, 0,
4636 tag_debug_size_in_bits,
4637 tag_debug_align_in_bits,
4638 g->err_enumerators.items, g->err_enumerators.length,
4639 g->err_tag_type->di_type, "");
4640 ZigLLVMReplaceTemporary(g->dbuilder, g->builtin_types.entry_global_error_set->di_type, err_set_di_type);
4641 g->builtin_types.entry_global_error_set->di_type = err_set_di_type;
4642
4643 for (size_t i = 0; i < g->error_di_types.length; i += 1) {
4644 ZigLLVMDIType **di_type_ptr = g->error_di_types.at(i);
4645 *di_type_ptr = err_set_di_type;
4646 }
4647 }
4648
4578 generate_error_name_table(g);4649 generate_error_name_table(g);
4579 generate_enum_name_tables(g);4650 generate_enum_name_tables(g);
45804651
...@@ -5176,16 +5247,24 @@ static void define_builtin_types(CodeGen *g) {...@@ -5176,16 +5247,24 @@ static void define_builtin_types(CodeGen *g) {
5176 }5247 }
51775248
5178 {5249 {
5179 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError);5250 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorSet);
5180 buf_init_from_str(&entry->name, "error");5251 buf_init_from_str(&entry->name, "error");
5252 entry->data.error_set.err_count = UINT32_MAX;
51815253
5182 // TODO allow overriding this type and keep track of max value and emit an5254 // TODO allow overriding this type and keep track of max value and emit an
5183 // error if there are too many errors declared5255 // error if there are too many errors declared
5184 g->err_tag_type = g->builtin_types.entry_u16;5256 g->err_tag_type = g->builtin_types.entry_u16;
51855257
5186 g->builtin_types.entry_pure_error = entry;5258 g->builtin_types.entry_global_error_set = entry;
5187 entry->type_ref = g->err_tag_type->type_ref;5259 entry->type_ref = g->err_tag_type->type_ref;
5188 entry->di_type = g->err_tag_type->di_type;5260
5261 entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
5262 ZigLLVMTag_DW_enumeration_type(), "error",
5263 ZigLLVMCompileUnitToScope(g->compile_unit), nullptr, 0);
5264
5265 // reserve index 0 to indicate no error
5266 g->err_enumerators.append(ZigLLVMCreateDebugEnumerator(g->dbuilder, "(none)", 0));
5267 g->errors_by_index.append(nullptr);
51895268
5190 g->primitive_type_table.put(&entry->name, entry);5269 g->primitive_type_table.put(&entry->name, entry);
5191 }5270 }
...@@ -5815,7 +5894,7 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry...@@ -5815,7 +5894,7 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry
5815 case TypeTableEntryIdBoundFn:5894 case TypeTableEntryIdBoundFn:
5816 case TypeTableEntryIdArgTuple:5895 case TypeTableEntryIdArgTuple:
5817 case TypeTableEntryIdErrorUnion:5896 case TypeTableEntryIdErrorUnion:
5818 case TypeTableEntryIdPureError:5897 case TypeTableEntryIdErrorSet:
5819 zig_unreachable();5898 zig_unreachable();
5820 case TypeTableEntryIdVoid:5899 case TypeTableEntryIdVoid:
5821 case TypeTableEntryIdUnreachable:5900 case TypeTableEntryIdUnreachable:
...@@ -5988,7 +6067,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf...@@ -5988,7 +6067,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
5988 return;6067 return;
5989 }6068 }
5990 case TypeTableEntryIdErrorUnion:6069 case TypeTableEntryIdErrorUnion:
5991 case TypeTableEntryIdPureError:6070 case TypeTableEntryIdErrorSet:
5992 case TypeTableEntryIdFn:6071 case TypeTableEntryIdFn:
5993 zig_panic("TODO implement get_c_type for more types");6072 zig_panic("TODO implement get_c_type for more types");
5994 case TypeTableEntryIdInvalid:6073 case TypeTableEntryIdInvalid:
...@@ -6155,7 +6234,7 @@ static void gen_h_file(CodeGen *g) {...@@ -6155,7 +6234,7 @@ static void gen_h_file(CodeGen *g) {
6155 case TypeTableEntryIdUndefLit:6234 case TypeTableEntryIdUndefLit:
6156 case TypeTableEntryIdNullLit:6235 case TypeTableEntryIdNullLit:
6157 case TypeTableEntryIdErrorUnion:6236 case TypeTableEntryIdErrorUnion:
6158 case TypeTableEntryIdPureError:6237 case TypeTableEntryIdErrorSet:
6159 case TypeTableEntryIdNamespace:6238 case TypeTableEntryIdNamespace:
6160 case TypeTableEntryIdBlock:6239 case TypeTableEntryIdBlock:
6161 case TypeTableEntryIdBoundFn:6240 case TypeTableEntryIdBoundFn:
...@@ -6265,3 +6344,4 @@ PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir,...@@ -6265,3 +6344,4 @@ PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir,
6265 }6344 }
6266 return pkg;6345 return pkg;
6267}6346}
6347
src/codegen.hpp+1
...@@ -36,6 +36,7 @@ void codegen_set_kernel32_lib_dir(CodeGen *codegen, Buf *kernel32_lib_dir);...@@ -36,6 +36,7 @@ void codegen_set_kernel32_lib_dir(CodeGen *codegen, Buf *kernel32_lib_dir);
36void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker);36void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker);
37void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole);37void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole);
38void codegen_add_lib_dir(CodeGen *codegen, const char *dir);38void codegen_add_lib_dir(CodeGen *codegen, const char *dir);
39void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib);
39LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib);40LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib);
40void codegen_add_framework(CodeGen *codegen, const char *name);41void codegen_add_framework(CodeGen *codegen, const char *name);
41void codegen_add_rpath(CodeGen *codegen, const char *name);42void codegen_add_rpath(CodeGen *codegen, const char *name);
src/ir.cpp+1428-232
...@@ -45,6 +45,59 @@ static LVal make_lval_addr(bool is_const, bool is_volatile) {...@@ -45,6 +45,59 @@ static LVal make_lval_addr(bool is_const, bool is_volatile) {
45 return { true, is_const, is_volatile };45 return { true, is_const, is_volatile };
46}46}
4747
48enum ConstCastResultId {
49 ConstCastResultIdOk,
50 ConstCastResultIdErrSet,
51 ConstCastResultIdErrSetGlobal,
52 ConstCastResultIdPointerChild,
53 ConstCastResultIdSliceChild,
54 ConstCastResultIdNullableChild,
55 ConstCastResultIdErrorUnionPayload,
56 ConstCastResultIdErrorUnionErrorSet,
57 ConstCastResultIdFnAlign,
58 ConstCastResultIdFnCC,
59 ConstCastResultIdFnVarArgs,
60 ConstCastResultIdFnIsGeneric,
61 ConstCastResultIdFnReturnType,
62 ConstCastResultIdFnArgCount,
63 ConstCastResultIdFnGenericArgCount,
64 ConstCastResultIdFnArg,
65 ConstCastResultIdFnArgNoAlias,
66 ConstCastResultIdType,
67 ConstCastResultIdUnresolvedInferredErrSet,
68};
69
70struct ConstCastErrSetMismatch {
71 ZigList<ErrorTableEntry *> missing_errors;
72};
73
74struct ConstCastOnly;
75
76struct ConstCastArg {
77 size_t arg_index;
78 ConstCastOnly *child;
79};
80
81struct ConstCastArgNoAlias {
82 size_t arg_index;
83};
84
85struct ConstCastOnly {
86 ConstCastResultId id;
87 union {
88 ConstCastErrSetMismatch error_set;
89 ConstCastOnly *pointer_child;
90 ConstCastOnly *slice_child;
91 ConstCastOnly *nullable_child;
92 ConstCastOnly *error_union_payload;
93 ConstCastOnly *error_union_error_set;
94 ConstCastOnly *return_type;
95 ConstCastArg fn_arg;
96 ConstCastArgNoAlias arg_no_alias;
97 } data;
98};
99
100
48static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);101static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
49static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval);102static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval);
50static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);103static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);
...@@ -580,6 +633,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorReturnTrace...@@ -580,6 +633,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorReturnTrace
580 return IrInstructionIdErrorReturnTrace;633 return IrInstructionIdErrorReturnTrace;
581}634}
582635
636static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnion *) {
637 return IrInstructionIdErrorUnion;
638}
639
583template<typename T>640template<typename T>
584static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {641static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
585 T *special_instruction = allocate<T>(1);642 T *special_instruction = allocate<T>(1);
...@@ -2326,6 +2383,19 @@ static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope,...@@ -2326,6 +2383,19 @@ static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope,
2326 return &instruction->base;2383 return &instruction->base;
2327}2384}
23282385
2386static IrInstruction *ir_build_error_union(IrBuilder *irb, Scope *scope, AstNode *source_node,
2387 IrInstruction *err_set, IrInstruction *payload)
2388{
2389 IrInstructionErrorUnion *instruction = ir_build_instruction<IrInstructionErrorUnion>(irb, scope, source_node);
2390 instruction->err_set = err_set;
2391 instruction->payload = payload;
2392
2393 ir_ref_instruction(err_set, irb->current_basic_block);
2394 ir_ref_instruction(payload, irb->current_basic_block);
2395
2396 return &instruction->base;
2397}
2398
2329static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {2399static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
2330 results[ReturnKindUnconditional] = 0;2400 results[ReturnKindUnconditional] = 0;
2331 results[ReturnKindError] = 0;2401 results[ReturnKindError] = 0;
...@@ -2800,6 +2870,23 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As...@@ -2800,6 +2870,23 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As
2800 return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values);2870 return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values);
2801}2871}
28022872
2873static IrInstruction *ir_gen_error_union(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
2874 assert(node->type == NodeTypeBinOpExpr);
2875
2876 AstNode *op1_node = node->data.bin_op_expr.op1;
2877 AstNode *op2_node = node->data.bin_op_expr.op2;
2878
2879 IrInstruction *err_set = ir_gen_node(irb, op1_node, parent_scope);
2880 if (err_set == irb->codegen->invalid_instruction)
2881 return irb->codegen->invalid_instruction;
2882
2883 IrInstruction *payload = ir_gen_node(irb, op2_node, parent_scope);
2884 if (payload == irb->codegen->invalid_instruction)
2885 return irb->codegen->invalid_instruction;
2886
2887 return ir_build_error_union(irb, parent_scope, node, err_set, payload);
2888}
2889
2803static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) {2890static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) {
2804 assert(node->type == NodeTypeBinOpExpr);2891 assert(node->type == NodeTypeBinOpExpr);
28052892
...@@ -2835,10 +2922,8 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)...@@ -2835,10 +2922,8 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
2835 return ir_gen_assign_op(irb, scope, node, IrBinOpBinXor);2922 return ir_gen_assign_op(irb, scope, node, IrBinOpBinXor);
2836 case BinOpTypeAssignBitOr:2923 case BinOpTypeAssignBitOr:
2837 return ir_gen_assign_op(irb, scope, node, IrBinOpBinOr);2924 return ir_gen_assign_op(irb, scope, node, IrBinOpBinOr);
2838 case BinOpTypeAssignBoolAnd:2925 case BinOpTypeAssignMergeErrorSets:
2839 return ir_gen_assign_op(irb, scope, node, IrBinOpBoolAnd);2926 return ir_gen_assign_op(irb, scope, node, IrBinOpMergeErrorSets);
2840 case BinOpTypeAssignBoolOr:
2841 return ir_gen_assign_op(irb, scope, node, IrBinOpBoolOr);
2842 case BinOpTypeBoolOr:2927 case BinOpTypeBoolOr:
2843 return ir_gen_bool_or(irb, scope, node);2928 return ir_gen_bool_or(irb, scope, node);
2844 case BinOpTypeBoolAnd:2929 case BinOpTypeBoolAnd:
...@@ -2885,8 +2970,12 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)...@@ -2885,8 +2970,12 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
2885 return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat);2970 return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat);
2886 case BinOpTypeArrayMult:2971 case BinOpTypeArrayMult:
2887 return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult);2972 return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult);
2973 case BinOpTypeMergeErrorSets:
2974 return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets);
2888 case BinOpTypeUnwrapMaybe:2975 case BinOpTypeUnwrapMaybe:
2889 return ir_gen_maybe_ok_or(irb, scope, node);2976 return ir_gen_maybe_ok_or(irb, scope, node);
2977 case BinOpTypeErrorUnion:
2978 return ir_gen_error_union(irb, scope, node);
2890 }2979 }
2891 zig_unreachable();2980 zig_unreachable();
2892}2981}
...@@ -3990,8 +4079,6 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod...@@ -3990,8 +4079,6 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
3990 return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval);4079 return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval);
3991 case PrefixOpMaybe:4080 case PrefixOpMaybe:
3992 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe), lval);4081 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe), lval);
3993 case PrefixOpError:
3994 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpError), lval);
3995 case PrefixOpUnwrapMaybe:4082 case PrefixOpUnwrapMaybe:
3996 return ir_gen_maybe_assert_ok(irb, scope, node, lval);4083 return ir_gen_maybe_assert_ok(irb, scope, node, lval);
3997 }4084 }
...@@ -4713,12 +4800,8 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -4713,12 +4800,8 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
4713 IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse");4800 IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse");
4714 IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "TryEnd");4801 IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "TryEnd");
47154802
4716 IrInstruction *is_comptime;4803 bool force_comptime = ir_should_inline(irb->exec, scope);
4717 if (ir_should_inline(irb->exec, scope)) {4804 IrInstruction *is_comptime = force_comptime ? ir_build_const_bool(irb, scope, node, true) : ir_build_test_comptime(irb, scope, node, is_err);
4718 is_comptime = ir_build_const_bool(irb, scope, node, true);
4719 } else {
4720 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
4721 }
4722 ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime);4805 ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime);
47234806
4724 ir_set_cursor_at_end_and_append_block(irb, ok_block);4807 ir_set_cursor_at_end_and_append_block(irb, ok_block);
...@@ -4727,8 +4810,9 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -4727,8 +4810,9 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
4727 if (var_symbol) {4810 if (var_symbol) {
4728 IrInstruction *var_type = nullptr;4811 IrInstruction *var_type = nullptr;
4729 bool is_shadowable = false;4812 bool is_shadowable = false;
4813 IrInstruction *var_is_comptime = force_comptime ? ir_build_const_bool(irb, scope, node, true) : ir_build_test_comptime(irb, scope, node, err_val);
4730 VariableTableEntry *var = ir_create_var(irb, node, scope,4814 VariableTableEntry *var = ir_create_var(irb, node, scope,
4731 var_symbol, var_is_const, var_is_const, is_shadowable, is_comptime);4815 var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime);
47324816
4733 IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, scope, node, err_val_ptr, false);4817 IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, scope, node, err_val_ptr, false);
4734 IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, node, var_ptr_value);4818 IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, node, var_ptr_value);
...@@ -5165,7 +5249,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast...@@ -5165,7 +5249,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast
51655249
5166static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) {5250static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) {
5167 assert(node->type == NodeTypeErrorType);5251 assert(node->type == NodeTypeErrorType);
5168 return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_pure_error);5252 return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_global_error_set);
5169}5253}
51705254
5171static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode *node) {5255static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
...@@ -5249,8 +5333,6 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN...@@ -5249,8 +5333,6 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
5249 Scope *err_scope;5333 Scope *err_scope;
5250 if (var_node) {5334 if (var_node) {
5251 assert(var_node->type == NodeTypeSymbol);5335 assert(var_node->type == NodeTypeSymbol);
5252 IrInstruction *var_type = ir_build_const_type(irb, parent_scope, node,
5253 irb->codegen->builtin_types.entry_pure_error);
5254 Buf *var_name = var_node->data.symbol_expr.symbol;5336 Buf *var_name = var_node->data.symbol_expr.symbol;
5255 bool is_const = true;5337 bool is_const = true;
5256 bool is_shadowable = false;5338 bool is_shadowable = false;
...@@ -5258,7 +5340,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN...@@ -5258,7 +5340,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
5258 is_const, is_const, is_shadowable, is_comptime);5340 is_const, is_const, is_shadowable, is_comptime);
5259 err_scope = var->child_scope;5341 err_scope = var->child_scope;
5260 IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr);5342 IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr);
5261 ir_build_var_decl(irb, err_scope, var_node, var, var_type, nullptr, err_val);5343 ir_build_var_decl(irb, err_scope, var_node, var, nullptr, nullptr, err_val);
5262 } else {5344 } else {
5263 err_scope = parent_scope;5345 err_scope = parent_scope;
5264 }5346 }
...@@ -5348,6 +5430,135 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope,...@@ -5348,6 +5430,135 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope,
5348 return ir_build_const_type(irb, parent_scope, node, container_type);5430 return ir_build_const_type(irb, parent_scope, node, container_type);
5349}5431}
53505432
5433// errors should be populated with set1's values
5434static TypeTableEntry *get_error_set_union(CodeGen *g, ErrorTableEntry **errors, TypeTableEntry *set1, TypeTableEntry *set2) {
5435 assert(set1->id == TypeTableEntryIdErrorSet);
5436 assert(set2->id == TypeTableEntryIdErrorSet);
5437
5438 TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet);
5439 buf_resize(&err_set_type->name, 0);
5440 buf_appendf(&err_set_type->name, "error{");
5441
5442 for (uint32_t i = 0, count = set1->data.error_set.err_count; i < count; i += 1) {
5443 assert(errors[set1->data.error_set.errors[i]->value] == set1->data.error_set.errors[i]);
5444 }
5445
5446 uint32_t count = set1->data.error_set.err_count;
5447 for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) {
5448 ErrorTableEntry *error_entry = set2->data.error_set.errors[i];
5449 if (errors[error_entry->value] == nullptr) {
5450 count += 1;
5451 }
5452 }
5453
5454 err_set_type->is_copyable = true;
5455 err_set_type->type_ref = g->builtin_types.entry_global_error_set->type_ref;
5456 err_set_type->di_type = g->builtin_types.entry_global_error_set->di_type;
5457 err_set_type->data.error_set.err_count = count;
5458 err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(count);
5459
5460 for (uint32_t i = 0; i < set1->data.error_set.err_count; i += 1) {
5461 ErrorTableEntry *error_entry = set1->data.error_set.errors[i];
5462 buf_appendf(&err_set_type->name, "%s,", buf_ptr(&error_entry->name));
5463 err_set_type->data.error_set.errors[i] = error_entry;
5464 }
5465
5466 uint32_t index = set1->data.error_set.err_count;
5467 for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) {
5468 ErrorTableEntry *error_entry = set2->data.error_set.errors[i];
5469 if (errors[error_entry->value] == nullptr) {
5470 errors[error_entry->value] = error_entry;
5471 buf_appendf(&err_set_type->name, "%s,", buf_ptr(&error_entry->name));
5472 err_set_type->data.error_set.errors[index] = error_entry;
5473 index += 1;
5474 }
5475 }
5476 assert(index == count);
5477 assert(count != 0);
5478
5479 buf_appendf(&err_set_type->name, "}");
5480
5481 g->error_di_types.append(&err_set_type->di_type);
5482
5483 return err_set_type;
5484
5485}
5486
5487static TypeTableEntry *make_err_set_with_one_item(CodeGen *g, Scope *parent_scope, AstNode *node,
5488 ErrorTableEntry *err_entry)
5489{
5490 TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet);
5491 buf_resize(&err_set_type->name, 0);
5492 buf_appendf(&err_set_type->name, "error{%s}", buf_ptr(&err_entry->name));
5493 err_set_type->is_copyable = true;
5494 err_set_type->type_ref = g->builtin_types.entry_global_error_set->type_ref;
5495 err_set_type->di_type = g->builtin_types.entry_global_error_set->di_type;
5496 err_set_type->data.error_set.err_count = 1;
5497 err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(1);
5498
5499 g->error_di_types.append(&err_set_type->di_type);
5500
5501 err_set_type->data.error_set.errors[0] = err_entry;
5502
5503 return err_set_type;
5504}
5505
5506static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
5507 assert(node->type == NodeTypeErrorSetDecl);
5508
5509 uint32_t err_count = node->data.err_set_decl.decls.length;
5510
5511 Buf *type_name = get_anon_type_name(irb->codegen, irb->exec, "error set", node);
5512 TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet);
5513 buf_init_from_buf(&err_set_type->name, type_name);
5514 err_set_type->is_copyable = true;
5515 err_set_type->data.error_set.err_count = err_count;
5516
5517 if (err_count == 0) {
5518 err_set_type->zero_bits = true;
5519 err_set_type->di_type = irb->codegen->builtin_types.entry_void->di_type;
5520 } else {
5521 err_set_type->type_ref = irb->codegen->builtin_types.entry_global_error_set->type_ref;
5522 err_set_type->di_type = irb->codegen->builtin_types.entry_global_error_set->di_type;
5523 irb->codegen->error_di_types.append(&err_set_type->di_type);
5524 err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count);
5525 }
5526
5527 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(irb->codegen->errors_by_index.length + err_count);
5528
5529 for (uint32_t i = 0; i < err_count; i += 1) {
5530 AstNode *symbol_node = node->data.err_set_decl.decls.at(i);
5531 assert(symbol_node->type == NodeTypeSymbol);
5532 Buf *err_name = symbol_node->data.symbol_expr.symbol;
5533 ErrorTableEntry *err = allocate<ErrorTableEntry>(1);
5534 err->decl_node = symbol_node;
5535 buf_init_from_buf(&err->name, err_name);
5536
5537 auto existing_entry = irb->codegen->error_table.put_unique(err_name, err);
5538 if (existing_entry) {
5539 err->value = existing_entry->value->value;
5540 } else {
5541 size_t error_value_count = irb->codegen->errors_by_index.length;
5542 assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)irb->codegen->err_tag_type->data.integral.bit_count));
5543 err->value = error_value_count;
5544 irb->codegen->errors_by_index.append(err);
5545 irb->codegen->err_enumerators.append(ZigLLVMCreateDebugEnumerator(irb->codegen->dbuilder,
5546 buf_ptr(err_name), error_value_count));
5547 }
5548 err_set_type->data.error_set.errors[i] = err;
5549
5550 ErrorTableEntry *prev_err = errors[err->value];
5551 if (prev_err != nullptr) {
5552 ErrorMsg *msg = add_node_error(irb->codegen, err->decl_node, buf_sprintf("duplicate error: '%s'", buf_ptr(&err->name)));
5553 add_error_note(irb->codegen, msg, prev_err->decl_node, buf_sprintf("other error here"));
5554 return irb->codegen->invalid_instruction;
5555 }
5556 errors[err->value] = err;
5557 }
5558 free(errors);
5559 return ir_build_const_type(irb, parent_scope, node, err_set_type);
5560}
5561
5351static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNode *node) {5562static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
5352 assert(node->type == NodeTypeFnProto);5563 assert(node->type == NodeTypeFnProto);
53535564
...@@ -5401,7 +5612,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop...@@ -5401,7 +5612,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
5401 case NodeTypeStructField:5612 case NodeTypeStructField:
5402 case NodeTypeFnDef:5613 case NodeTypeFnDef:
5403 case NodeTypeFnDecl:5614 case NodeTypeFnDecl:
5404 case NodeTypeErrorValueDecl:
5405 case NodeTypeTestDecl:5615 case NodeTypeTestDecl:
5406 zig_unreachable();5616 zig_unreachable();
5407 case NodeTypeBlock:5617 case NodeTypeBlock:
...@@ -5482,6 +5692,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop...@@ -5482,6 +5692,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
5482 return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval);5692 return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval);
5483 case NodeTypeFnProto:5693 case NodeTypeFnProto:
5484 return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval);5694 return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval);
5695 case NodeTypeErrorSetDecl:
5696 return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval);
5485 }5697 }
5486 zig_unreachable();5698 zig_unreachable();
5487}5699}
...@@ -6287,6 +6499,274 @@ static bool slice_is_const(TypeTableEntry *type) {...@@ -6287,6 +6499,274 @@ static bool slice_is_const(TypeTableEntry *type) {
6287 return type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;6499 return type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
6288}6500}
62896501
6502static bool resolve_inferred_error_set(IrAnalyze *ira, TypeTableEntry *err_set_type, AstNode *source_node) {
6503 assert(err_set_type->id == TypeTableEntryIdErrorSet);
6504 FnTableEntry *infer_fn = err_set_type->data.error_set.infer_fn;
6505 if (infer_fn != nullptr) {
6506 if (infer_fn->anal_state == FnAnalStateInvalid) {
6507 return false;
6508 } else if (infer_fn->anal_state == FnAnalStateReady) {
6509 analyze_fn_body(ira->codegen, infer_fn);
6510 if (err_set_type->data.error_set.infer_fn != nullptr) {
6511 assert(ira->codegen->errors.length != 0);
6512 return false;
6513 }
6514 } else {
6515 ir_add_error_node(ira, source_node,
6516 buf_sprintf("cannot resolve inferred error set '%s': function '%s' not fully analyzed yet",
6517 buf_ptr(&err_set_type->name), buf_ptr(&err_set_type->data.error_set.infer_fn->symbol_name)));
6518 return false;
6519 }
6520 }
6521 return true;
6522}
6523
6524static TypeTableEntry *get_error_set_intersection(IrAnalyze *ira, TypeTableEntry *set1, TypeTableEntry *set2,
6525 AstNode *source_node)
6526{
6527 assert(set1->id == TypeTableEntryIdErrorSet);
6528 assert(set2->id == TypeTableEntryIdErrorSet);
6529
6530 if (!resolve_inferred_error_set(ira, set1, source_node)) {
6531 return ira->codegen->builtin_types.entry_invalid;
6532 }
6533 if (!resolve_inferred_error_set(ira, set2, source_node)) {
6534 return ira->codegen->builtin_types.entry_invalid;
6535 }
6536 if (type_is_global_error_set(set1)) {
6537 return set2;
6538 }
6539 if (type_is_global_error_set(set2)) {
6540 return set1;
6541 }
6542 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
6543 for (uint32_t i = 0; i < set1->data.error_set.err_count; i += 1) {
6544 ErrorTableEntry *error_entry = set1->data.error_set.errors[i];
6545 assert(errors[error_entry->value] == nullptr);
6546 errors[error_entry->value] = error_entry;
6547 }
6548 ZigList<ErrorTableEntry *> intersection_list = {};
6549
6550 TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet);
6551 buf_resize(&err_set_type->name, 0);
6552 buf_appendf(&err_set_type->name, "error{");
6553
6554 for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) {
6555 ErrorTableEntry *error_entry = set2->data.error_set.errors[i];
6556 ErrorTableEntry *existing_entry = errors[error_entry->value];
6557 if (existing_entry != nullptr) {
6558 intersection_list.append(existing_entry);
6559 buf_appendf(&err_set_type->name, "%s,", buf_ptr(&existing_entry->name));
6560 }
6561 }
6562 free(errors);
6563
6564 err_set_type->is_copyable = true;
6565 err_set_type->type_ref = ira->codegen->builtin_types.entry_global_error_set->type_ref;
6566 err_set_type->di_type = ira->codegen->builtin_types.entry_global_error_set->di_type;
6567 err_set_type->data.error_set.err_count = intersection_list.length;
6568 err_set_type->data.error_set.errors = intersection_list.items;
6569 err_set_type->zero_bits = intersection_list.length == 0;
6570
6571 buf_appendf(&err_set_type->name, "}");
6572
6573 ira->codegen->error_di_types.append(&err_set_type->di_type);
6574
6575 return err_set_type;
6576}
6577
6578
6579static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry *expected_type,
6580 TypeTableEntry *actual_type, AstNode *source_node)
6581{
6582 CodeGen *g = ira->codegen;
6583 ConstCastOnly result = {};
6584 result.id = ConstCastResultIdOk;
6585
6586 if (expected_type == actual_type)
6587 return result;
6588
6589 // pointer const
6590 if (expected_type->id == TypeTableEntryIdPointer &&
6591 actual_type->id == TypeTableEntryIdPointer &&
6592 (!actual_type->data.pointer.is_const || expected_type->data.pointer.is_const) &&
6593 (!actual_type->data.pointer.is_volatile || expected_type->data.pointer.is_volatile) &&
6594 actual_type->data.pointer.bit_offset == expected_type->data.pointer.bit_offset &&
6595 actual_type->data.pointer.unaligned_bit_count == expected_type->data.pointer.unaligned_bit_count &&
6596 actual_type->data.pointer.alignment >= expected_type->data.pointer.alignment)
6597 {
6598 ConstCastOnly child = types_match_const_cast_only(ira, expected_type->data.pointer.child_type, actual_type->data.pointer.child_type, source_node);
6599 if (child.id != ConstCastResultIdOk) {
6600 result.id = ConstCastResultIdPointerChild;
6601 result.data.pointer_child = allocate_nonzero<ConstCastOnly>(1);
6602 *result.data.pointer_child = child;
6603 }
6604 return result;
6605 }
6606
6607 // slice const
6608 if (is_slice(expected_type) && is_slice(actual_type)) {
6609 TypeTableEntry *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index].type_entry;
6610 TypeTableEntry *expected_ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry;
6611 if ((!actual_ptr_type->data.pointer.is_const || expected_ptr_type->data.pointer.is_const) &&
6612 (!actual_ptr_type->data.pointer.is_volatile || expected_ptr_type->data.pointer.is_volatile) &&
6613 actual_ptr_type->data.pointer.bit_offset == expected_ptr_type->data.pointer.bit_offset &&
6614 actual_ptr_type->data.pointer.unaligned_bit_count == expected_ptr_type->data.pointer.unaligned_bit_count &&
6615 actual_ptr_type->data.pointer.alignment >= expected_ptr_type->data.pointer.alignment)
6616 {
6617 ConstCastOnly child = types_match_const_cast_only(ira, expected_ptr_type->data.pointer.child_type,
6618 actual_ptr_type->data.pointer.child_type, source_node);
6619 if (child.id != ConstCastResultIdOk) {
6620 result.id = ConstCastResultIdSliceChild;
6621 result.data.slice_child = allocate_nonzero<ConstCastOnly>(1);
6622 *result.data.slice_child = child;
6623 }
6624 return result;
6625 }
6626 }
6627
6628 // maybe
6629 if (expected_type->id == TypeTableEntryIdMaybe && actual_type->id == TypeTableEntryIdMaybe) {
6630 ConstCastOnly child = types_match_const_cast_only(ira, expected_type->data.maybe.child_type, actual_type->data.maybe.child_type, source_node);
6631 if (child.id != ConstCastResultIdOk) {
6632 result.id = ConstCastResultIdNullableChild;
6633 result.data.nullable_child = allocate_nonzero<ConstCastOnly>(1);
6634 *result.data.nullable_child = child;
6635 }
6636 return result;
6637 }
6638
6639 // error union
6640 if (expected_type->id == TypeTableEntryIdErrorUnion && actual_type->id == TypeTableEntryIdErrorUnion) {
6641 ConstCastOnly payload_child = types_match_const_cast_only(ira, expected_type->data.error_union.payload_type, actual_type->data.error_union.payload_type, source_node);
6642 if (payload_child.id != ConstCastResultIdOk) {
6643 result.id = ConstCastResultIdErrorUnionPayload;
6644 result.data.error_union_payload = allocate_nonzero<ConstCastOnly>(1);
6645 *result.data.error_union_payload = payload_child;
6646 return result;
6647 }
6648 ConstCastOnly error_set_child = types_match_const_cast_only(ira, expected_type->data.error_union.err_set_type, actual_type->data.error_union.err_set_type, source_node);
6649 if (error_set_child.id != ConstCastResultIdOk) {
6650 result.id = ConstCastResultIdErrorUnionErrorSet;
6651 result.data.error_union_error_set = allocate_nonzero<ConstCastOnly>(1);
6652 *result.data.error_union_error_set = error_set_child;
6653 return result;
6654 }
6655 return result;
6656 }
6657
6658 // error set
6659 if (expected_type->id == TypeTableEntryIdErrorSet && actual_type->id == TypeTableEntryIdErrorSet) {
6660 TypeTableEntry *contained_set = actual_type;
6661 TypeTableEntry *container_set = expected_type;
6662
6663 // if the container set is inferred, then this will always work.
6664 if (container_set->data.error_set.infer_fn != nullptr) {
6665 return result;
6666 }
6667 // if the container set is the global one, it will always work.
6668 if (type_is_global_error_set(container_set)) {
6669 return result;
6670 }
6671
6672 if (!resolve_inferred_error_set(ira, contained_set, source_node)) {
6673 result.id = ConstCastResultIdUnresolvedInferredErrSet;
6674 return result;
6675 }
6676
6677 if (type_is_global_error_set(contained_set)) {
6678 result.id = ConstCastResultIdErrSetGlobal;
6679 return result;
6680 }
6681
6682 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(g->errors_by_index.length);
6683 for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) {
6684 ErrorTableEntry *error_entry = container_set->data.error_set.errors[i];
6685 assert(errors[error_entry->value] == nullptr);
6686 errors[error_entry->value] = error_entry;
6687 }
6688 for (uint32_t i = 0; i < contained_set->data.error_set.err_count; i += 1) {
6689 ErrorTableEntry *contained_error_entry = contained_set->data.error_set.errors[i];
6690 ErrorTableEntry *error_entry = errors[contained_error_entry->value];
6691 if (error_entry == nullptr) {
6692 if (result.id == ConstCastResultIdOk) {
6693 result.id = ConstCastResultIdErrSet;
6694 }
6695 result.data.error_set.missing_errors.append(contained_error_entry);
6696 }
6697 }
6698 free(errors);
6699 return result;
6700 }
6701
6702 // fn
6703 if (expected_type->id == TypeTableEntryIdFn &&
6704 actual_type->id == TypeTableEntryIdFn)
6705 {
6706 if (expected_type->data.fn.fn_type_id.alignment > actual_type->data.fn.fn_type_id.alignment) {
6707 result.id = ConstCastResultIdFnAlign;
6708 return result;
6709 }
6710 if (expected_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) {
6711 result.id = ConstCastResultIdFnCC;
6712 return result;
6713 }
6714 if (expected_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {
6715 result.id = ConstCastResultIdFnVarArgs;
6716 return result;
6717 }
6718 if (expected_type->data.fn.is_generic != actual_type->data.fn.is_generic) {
6719 result.id = ConstCastResultIdFnIsGeneric;
6720 return result;
6721 }
6722 if (!expected_type->data.fn.is_generic &&
6723 actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable)
6724 {
6725 ConstCastOnly child = types_match_const_cast_only(ira, expected_type->data.fn.fn_type_id.return_type, actual_type->data.fn.fn_type_id.return_type, source_node);
6726 if (child.id != ConstCastResultIdOk) {
6727 result.id = ConstCastResultIdFnReturnType;
6728 result.data.return_type = allocate_nonzero<ConstCastOnly>(1);
6729 *result.data.return_type = child;
6730 }
6731 return result;
6732 }
6733 if (expected_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {
6734 result.id = ConstCastResultIdFnArgCount;
6735 return result;
6736 }
6737 if (expected_type->data.fn.fn_type_id.next_param_index != actual_type->data.fn.fn_type_id.next_param_index) {
6738 result.id = ConstCastResultIdFnGenericArgCount;
6739 return result;
6740 }
6741 assert(expected_type->data.fn.is_generic ||
6742 expected_type->data.fn.fn_type_id.next_param_index == expected_type->data.fn.fn_type_id.param_count);
6743 for (size_t i = 0; i < expected_type->data.fn.fn_type_id.next_param_index; i += 1) {
6744 // note it's reversed for parameters
6745 FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i];
6746 FnTypeParamInfo *expected_param_info = &expected_type->data.fn.fn_type_id.param_info[i];
6747
6748 ConstCastOnly arg_child = types_match_const_cast_only(ira, actual_param_info->type, expected_param_info->type, source_node);
6749 if (arg_child.id != ConstCastResultIdOk) {
6750 result.id = ConstCastResultIdFnArg;
6751 result.data.fn_arg.arg_index = i;
6752 result.data.fn_arg.child = allocate_nonzero<ConstCastOnly>(1);
6753 *result.data.fn_arg.child = arg_child;
6754 return result;
6755 }
6756
6757 if (expected_param_info->is_noalias != actual_param_info->is_noalias) {
6758 result.id = ConstCastResultIdFnArgNoAlias;
6759 result.data.arg_no_alias.arg_index = i;
6760 return result;
6761 }
6762 }
6763 return result;
6764 }
6765
6766 result.id = ConstCastResultIdType;
6767 return result;
6768}
6769
6290enum ImplicitCastMatchResult {6770enum ImplicitCastMatchResult {
6291 ImplicitCastMatchResultNo,6771 ImplicitCastMatchResultNo,
6292 ImplicitCastMatchResultYes,6772 ImplicitCastMatchResultYes,
...@@ -6296,10 +6776,46 @@ enum ImplicitCastMatchResult {...@@ -6296,10 +6776,46 @@ enum ImplicitCastMatchResult {
6296static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, TypeTableEntry *expected_type,6776static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, TypeTableEntry *expected_type,
6297 TypeTableEntry *actual_type, IrInstruction *value)6777 TypeTableEntry *actual_type, IrInstruction *value)
6298{6778{
6299 if (types_match_const_cast_only(expected_type, actual_type)) {6779 AstNode *source_node = value->source_node;
6780 ConstCastOnly const_cast_result = types_match_const_cast_only(ira, expected_type, actual_type, source_node);
6781 if (const_cast_result.id == ConstCastResultIdOk) {
6300 return ImplicitCastMatchResultYes;6782 return ImplicitCastMatchResultYes;
6301 }6783 }
63026784
6785 // if we got here with error sets, make an error showing the incompatibilities
6786 ZigList<ErrorTableEntry *> *missing_errors = nullptr;
6787 if (const_cast_result.id == ConstCastResultIdErrSet) {
6788 missing_errors = &const_cast_result.data.error_set.missing_errors;
6789 }
6790 if (const_cast_result.id == ConstCastResultIdErrorUnionErrorSet) {
6791 if (const_cast_result.data.error_union_error_set->id == ConstCastResultIdErrSet) {
6792 missing_errors = &const_cast_result.data.error_union_error_set->data.error_set.missing_errors;
6793 } else if (const_cast_result.data.error_union_error_set->id == ConstCastResultIdErrSetGlobal) {
6794 ErrorMsg *msg = ir_add_error(ira, value,
6795 buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));
6796 add_error_note(ira->codegen, msg, value->source_node,
6797 buf_sprintf("unable to cast global error set into smaller set"));
6798 return ImplicitCastMatchResultReportedError;
6799 }
6800 } else if (const_cast_result.id == ConstCastResultIdErrSetGlobal) {
6801 ErrorMsg *msg = ir_add_error(ira, value,
6802 buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));
6803 add_error_note(ira->codegen, msg, value->source_node,
6804 buf_sprintf("unable to cast global error set into smaller set"));
6805 return ImplicitCastMatchResultReportedError;
6806 }
6807 if (missing_errors != nullptr) {
6808 ErrorMsg *msg = ir_add_error(ira, value,
6809 buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));
6810 for (size_t i = 0; i < missing_errors->length; i += 1) {
6811 ErrorTableEntry *error_entry = missing_errors->at(i);
6812 add_error_note(ira->codegen, msg, error_entry->decl_node,
6813 buf_sprintf("'error.%s' not a member of destination error set", buf_ptr(&error_entry->name)));
6814 }
6815
6816 return ImplicitCastMatchResultReportedError;
6817 }
6818
6303 // implicit conversion from anything to var6819 // implicit conversion from anything to var
6304 if (expected_type->id == TypeTableEntryIdVar) {6820 if (expected_type->id == TypeTableEntryIdVar) {
6305 return ImplicitCastMatchResultYes;6821 return ImplicitCastMatchResultYes;
...@@ -6319,25 +6835,25 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,...@@ -6319,25 +6835,25 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
6319 return ImplicitCastMatchResultYes;6835 return ImplicitCastMatchResultYes;
6320 }6836 }
63216837
6322 // implicit T to %T6838 // implicit T to U!T
6323 if (expected_type->id == TypeTableEntryIdErrorUnion &&6839 if (expected_type->id == TypeTableEntryIdErrorUnion &&
6324 ir_types_match_with_implicit_cast(ira, expected_type->data.error.child_type, actual_type, value))6840 ir_types_match_with_implicit_cast(ira, expected_type->data.error_union.payload_type, actual_type, value))
6325 {6841 {
6326 return ImplicitCastMatchResultYes;6842 return ImplicitCastMatchResultYes;
6327 }6843 }
63286844
6329 // implicit conversion from pure error to error union type6845 // implicit conversion from error set to error union type
6330 if (expected_type->id == TypeTableEntryIdErrorUnion &&6846 if (expected_type->id == TypeTableEntryIdErrorUnion &&
6331 actual_type->id == TypeTableEntryIdPureError)6847 actual_type->id == TypeTableEntryIdErrorSet)
6332 {6848 {
6333 return ImplicitCastMatchResultYes;6849 return ImplicitCastMatchResultYes;
6334 }6850 }
63356851
6336 // implicit conversion from T to %?T6852 // implicit conversion from T to U!?T
6337 if (expected_type->id == TypeTableEntryIdErrorUnion &&6853 if (expected_type->id == TypeTableEntryIdErrorUnion &&
6338 expected_type->data.error.child_type->id == TypeTableEntryIdMaybe &&6854 expected_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe &&
6339 ir_types_match_with_implicit_cast(ira,6855 ir_types_match_with_implicit_cast(ira,
6340 expected_type->data.error.child_type->data.maybe.child_type,6856 expected_type->data.error_union.payload_type->data.maybe.child_type,
6341 actual_type, value))6857 actual_type, value))
6342 {6858 {
6343 return ImplicitCastMatchResultYes;6859 return ImplicitCastMatchResultYes;
...@@ -6374,7 +6890,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,...@@ -6374,7 +6890,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
6374 assert(ptr_type->id == TypeTableEntryIdPointer);6890 assert(ptr_type->id == TypeTableEntryIdPointer);
63756891
6376 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&6892 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
6377 types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type))6893 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
6378 {6894 {
6379 return ImplicitCastMatchResultYes;6895 return ImplicitCastMatchResultYes;
6380 }6896 }
...@@ -6392,7 +6908,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,...@@ -6392,7 +6908,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
6392 TypeTableEntry *array_type = actual_type->data.pointer.child_type;6908 TypeTableEntry *array_type = actual_type->data.pointer.child_type;
63936909
6394 if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&6910 if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
6395 types_match_const_cast_only(ptr_type->data.pointer.child_type, array_type->data.array.child_type))6911 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
6396 {6912 {
6397 return ImplicitCastMatchResultYes;6913 return ImplicitCastMatchResultYes;
6398 }6914 }
...@@ -6408,7 +6924,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,...@@ -6408,7 +6924,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
6408 expected_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;6924 expected_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;
6409 assert(ptr_type->id == TypeTableEntryIdPointer);6925 assert(ptr_type->id == TypeTableEntryIdPointer);
6410 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&6926 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
6411 types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type))6927 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
6412 {6928 {
6413 return ImplicitCastMatchResultYes;6929 return ImplicitCastMatchResultYes;
6414 }6930 }
...@@ -6423,7 +6939,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,...@@ -6423,7 +6939,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
6423 expected_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;6939 expected_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;
6424 assert(ptr_type->id == TypeTableEntryIdPointer);6940 assert(ptr_type->id == TypeTableEntryIdPointer);
6425 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&6941 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
6426 types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type))6942 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
6427 {6943 {
6428 return ImplicitCastMatchResultYes;6944 return ImplicitCastMatchResultYes;
6429 }6945 }
...@@ -6503,7 +7019,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,...@@ -6503,7 +7019,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
6503 // implicitly take a const pointer to something7019 // implicitly take a const pointer to something
6504 if (!type_requires_comptime(actual_type)) {7020 if (!type_requires_comptime(actual_type)) {
6505 TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);7021 TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);
6506 if (types_match_const_cast_only(expected_type, const_ptr_actual)) {7022 if (types_match_const_cast_only(ira, expected_type, const_ptr_actual, source_node).id == ConstCastResultIdOk) {
6507 return ImplicitCastMatchResultYes;7023 return ImplicitCastMatchResultYes;
6508 }7024 }
6509 }7025 }
...@@ -6511,13 +7027,39 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,...@@ -6511,13 +7027,39 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
6511 return ImplicitCastMatchResultNo;7027 return ImplicitCastMatchResultNo;
6512}7028}
65137029
7030static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t *errors_count) {
7031 size_t old_errors_count = *errors_count;
7032 *errors_count = g->errors_by_index.length;
7033 *errors = reallocate(*errors, old_errors_count, *errors_count);
7034}
7035
6514static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) {7036static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) {
6515 assert(instruction_count >= 1);7037 assert(instruction_count >= 1);
6516 IrInstruction *prev_inst = instructions[0];7038 IrInstruction *prev_inst = instructions[0];
6517 if (type_is_invalid(prev_inst->value.type)) {7039 if (type_is_invalid(prev_inst->value.type)) {
6518 return ira->codegen->builtin_types.entry_invalid;7040 return ira->codegen->builtin_types.entry_invalid;
6519 }7041 }
6520 bool any_are_pure_error = (prev_inst->value.type->id == TypeTableEntryIdPureError);7042 ErrorTableEntry **errors = nullptr;
7043 size_t errors_count = 0;
7044 TypeTableEntry *err_set_type = nullptr;
7045 if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) {
7046 if (type_is_global_error_set(prev_inst->value.type)) {
7047 err_set_type = ira->codegen->builtin_types.entry_global_error_set;
7048 } else {
7049 err_set_type = prev_inst->value.type;
7050 if (!resolve_inferred_error_set(ira, err_set_type, prev_inst->source_node)) {
7051 return ira->codegen->builtin_types.entry_invalid;
7052 }
7053 update_errors_helper(ira->codegen, &errors, &errors_count);
7054
7055 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
7056 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
7057 assert(errors[error_entry->value] == nullptr);
7058 errors[error_entry->value] = error_entry;
7059 }
7060 }
7061 }
7062
6521 bool any_are_null = (prev_inst->value.type->id == TypeTableEntryIdNullLit);7063 bool any_are_null = (prev_inst->value.type->id == TypeTableEntryIdNullLit);
6522 bool convert_to_const_slice = false;7064 bool convert_to_const_slice = false;
6523 for (size_t i = 1; i < instruction_count; i += 1) {7065 for (size_t i = 1; i < instruction_count; i += 1) {
...@@ -6538,34 +7080,280 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -6538,34 +7080,280 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
6538 continue;7080 continue;
6539 }7081 }
65407082
6541 if (prev_type->id == TypeTableEntryIdPureError) {7083 if (prev_type->id == TypeTableEntryIdNullLit) {
6542 prev_inst = cur_inst;7084 prev_inst = cur_inst;
6543 continue;7085 continue;
6544 }7086 }
65457087
6546 if (prev_type->id == TypeTableEntryIdNullLit) {7088 if (cur_type->id == TypeTableEntryIdNullLit) {
6547 prev_inst = cur_inst;7089 any_are_null = true;
6548 continue;7090 continue;
6549 }7091 }
65507092
6551 if (cur_type->id == TypeTableEntryIdPureError) {7093 if (prev_type->id == TypeTableEntryIdErrorSet) {
7094 assert(err_set_type != nullptr);
7095 if (cur_type->id == TypeTableEntryIdErrorSet) {
7096 if (type_is_global_error_set(err_set_type)) {
7097 continue;
7098 }
7099 if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) {
7100 return ira->codegen->builtin_types.entry_invalid;
7101 }
7102 if (type_is_global_error_set(cur_type)) {
7103 err_set_type = ira->codegen->builtin_types.entry_global_error_set;
7104 prev_inst = cur_inst;
7105 continue;
7106 }
7107
7108 // number of declared errors might have increased now
7109 update_errors_helper(ira->codegen, &errors, &errors_count);
7110
7111 // if err_set_type is a superset of cur_type, keep err_set_type.
7112 // if cur_type is a superset of err_set_type, switch err_set_type to cur_type
7113 bool prev_is_superset = true;
7114 for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) {
7115 ErrorTableEntry *contained_error_entry = cur_type->data.error_set.errors[i];
7116 ErrorTableEntry *error_entry = errors[contained_error_entry->value];
7117 if (error_entry == nullptr) {
7118 prev_is_superset = false;
7119 break;
7120 }
7121 }
7122 if (prev_is_superset) {
7123 continue;
7124 }
7125
7126 // unset everything in errors
7127 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];
7129 errors[error_entry->value] = nullptr;
7130 }
7131 for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) {
7132 assert(errors[i] == nullptr);
7133 }
7134 for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) {
7135 ErrorTableEntry *error_entry = cur_type->data.error_set.errors[i];
7136 assert(errors[error_entry->value] == nullptr);
7137 errors[error_entry->value] = error_entry;
7138 }
7139 bool cur_is_superset = true;
7140 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
7141 ErrorTableEntry *contained_error_entry = err_set_type->data.error_set.errors[i];
7142 ErrorTableEntry *error_entry = errors[contained_error_entry->value];
7143 if (error_entry == nullptr) {
7144 cur_is_superset = false;
7145 break;
7146 }
7147 }
7148 if (cur_is_superset) {
7149 err_set_type = cur_type;
7150 prev_inst = cur_inst;
7151 assert(errors != nullptr);
7152 continue;
7153 }
7154
7155 // neither of them are supersets. so we invent a new error set type that is a union of both of them
7156 err_set_type = get_error_set_union(ira->codegen, errors, cur_type, err_set_type);
7157 assert(errors != nullptr);
7158 continue;
7159 } else if (cur_type->id == TypeTableEntryIdErrorUnion) {
7160 if (type_is_global_error_set(err_set_type)) {
7161 prev_inst = cur_inst;
7162 continue;
7163 }
7164 TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
7165 if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) {
7166 return ira->codegen->builtin_types.entry_invalid;
7167 }
7168 if (type_is_global_error_set(cur_err_set_type)) {
7169 err_set_type = ira->codegen->builtin_types.entry_global_error_set;
7170 prev_inst = cur_inst;
7171 continue;
7172 }
7173
7174 update_errors_helper(ira->codegen, &errors, &errors_count);
7175
7176 // test if err_set_type is a subset of cur_type's error set
7177 // unset everything in errors
7178 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
7179 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
7180 errors[error_entry->value] = nullptr;
7181 }
7182 for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) {
7183 assert(errors[i] == nullptr);
7184 }
7185 for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) {
7186 ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i];
7187 assert(errors[error_entry->value] == nullptr);
7188 errors[error_entry->value] = error_entry;
7189 }
7190 bool cur_is_superset = true;
7191 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
7192 ErrorTableEntry *contained_error_entry = err_set_type->data.error_set.errors[i];
7193 ErrorTableEntry *error_entry = errors[contained_error_entry->value];
7194 if (error_entry == nullptr) {
7195 cur_is_superset = false;
7196 break;
7197 }
7198 }
7199 if (cur_is_superset) {
7200 err_set_type = cur_err_set_type;
7201 prev_inst = cur_inst;
7202 assert(errors != nullptr);
7203 continue;
7204 }
7205
7206 // not a subset. invent new error set type, union of both of them
7207 err_set_type = get_error_set_union(ira->codegen, errors, cur_err_set_type, err_set_type);
7208 prev_inst = cur_inst;
7209 assert(errors != nullptr);
7210 continue;
7211 } else {
7212 prev_inst = cur_inst;
7213 continue;
7214 }
7215 }
7216
7217 if (cur_type->id == TypeTableEntryIdErrorSet) {
6552 if (prev_type->id == TypeTableEntryIdArray) {7218 if (prev_type->id == TypeTableEntryIdArray) {
6553 convert_to_const_slice = true;7219 convert_to_const_slice = true;
6554 }7220 }
6555 any_are_pure_error = true;7221 if (type_is_global_error_set(cur_type)) {
7222 err_set_type = ira->codegen->builtin_types.entry_global_error_set;
7223 continue;
7224 }
7225 if (err_set_type != nullptr && type_is_global_error_set(err_set_type)) {
7226 continue;
7227 }
7228 if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) {
7229 return ira->codegen->builtin_types.entry_invalid;
7230 }
7231
7232 update_errors_helper(ira->codegen, &errors, &errors_count);
7233
7234 if (err_set_type == nullptr) {
7235 if (prev_type->id == TypeTableEntryIdErrorUnion) {
7236 err_set_type = prev_type->data.error_union.err_set_type;
7237 } else {
7238 err_set_type = cur_type;
7239 }
7240 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
7241 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
7242 assert(errors[error_entry->value] == nullptr);
7243 errors[error_entry->value] = error_entry;
7244 }
7245 if (err_set_type == cur_type) {
7246 continue;
7247 }
7248 }
7249 // check if the cur type error set is a subset
7250 bool prev_is_superset = true;
7251 for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) {
7252 ErrorTableEntry *contained_error_entry = cur_type->data.error_set.errors[i];
7253 ErrorTableEntry *error_entry = errors[contained_error_entry->value];
7254 if (error_entry == nullptr) {
7255 prev_is_superset = false;
7256 break;
7257 }
7258 }
7259 if (prev_is_superset) {
7260 continue;
7261 }
7262 // not a subset. invent new error set type, union of both of them
7263 err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_type);
7264 assert(errors != nullptr);
6556 continue;7265 continue;
6557 }7266 }
65587267
6559 if (cur_type->id == TypeTableEntryIdNullLit) {7268 if (prev_type->id == TypeTableEntryIdErrorUnion && cur_type->id == TypeTableEntryIdErrorUnion) {
6560 any_are_null = true;7269 TypeTableEntry *prev_payload_type = prev_type->data.error_union.payload_type;
6561 continue;7270 TypeTableEntry *cur_payload_type = cur_type->data.error_union.payload_type;
7271
7272 bool const_cast_prev = types_match_const_cast_only(ira, prev_payload_type, cur_payload_type,
7273 source_node).id == ConstCastResultIdOk;
7274 bool const_cast_cur = types_match_const_cast_only(ira, cur_payload_type, prev_payload_type,
7275 source_node).id == ConstCastResultIdOk;
7276
7277 if (const_cast_prev || const_cast_cur) {
7278 if (const_cast_cur) {
7279 prev_inst = cur_inst;
7280 }
7281
7282 TypeTableEntry *prev_err_set_type = prev_type->data.error_union.err_set_type;
7283 TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
7284
7285 if (!resolve_inferred_error_set(ira, prev_err_set_type, cur_inst->source_node)) {
7286 return ira->codegen->builtin_types.entry_invalid;
7287 }
7288
7289 if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) {
7290 return ira->codegen->builtin_types.entry_invalid;
7291 }
7292
7293 if (type_is_global_error_set(prev_err_set_type) || type_is_global_error_set(cur_err_set_type)) {
7294 err_set_type = ira->codegen->builtin_types.entry_global_error_set;
7295 continue;
7296 }
7297
7298 update_errors_helper(ira->codegen, &errors, &errors_count);
7299
7300 if (err_set_type == nullptr) {
7301 err_set_type = prev_err_set_type;
7302 for (uint32_t i = 0; i < prev_err_set_type->data.error_set.err_count; i += 1) {
7303 ErrorTableEntry *error_entry = prev_err_set_type->data.error_set.errors[i];
7304 assert(errors[error_entry->value] == nullptr);
7305 errors[error_entry->value] = error_entry;
7306 }
7307 }
7308 bool prev_is_superset = true;
7309 for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) {
7310 ErrorTableEntry *contained_error_entry = cur_err_set_type->data.error_set.errors[i];
7311 ErrorTableEntry *error_entry = errors[contained_error_entry->value];
7312 if (error_entry == nullptr) {
7313 prev_is_superset = false;
7314 break;
7315 }
7316 }
7317 if (prev_is_superset) {
7318 continue;
7319 }
7320 // unset all the errors
7321 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
7322 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
7323 errors[error_entry->value] = nullptr;
7324 }
7325 for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) {
7326 assert(errors[i] == nullptr);
7327 }
7328 for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) {
7329 ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i];
7330 assert(errors[error_entry->value] == nullptr);
7331 errors[error_entry->value] = error_entry;
7332 }
7333 bool cur_is_superset = true;
7334 for (uint32_t i = 0; i < prev_err_set_type->data.error_set.err_count; i += 1) {
7335 ErrorTableEntry *contained_error_entry = prev_err_set_type->data.error_set.errors[i];
7336 ErrorTableEntry *error_entry = errors[contained_error_entry->value];
7337 if (error_entry == nullptr) {
7338 cur_is_superset = false;
7339 break;
7340 }
7341 }
7342 if (cur_is_superset) {
7343 err_set_type = cur_err_set_type;
7344 continue;
7345 }
7346
7347 err_set_type = get_error_set_union(ira->codegen, errors, cur_err_set_type, prev_err_set_type);
7348 continue;
7349 }
6562 }7350 }
65637351
6564 if (types_match_const_cast_only(prev_type, cur_type)) {7352 if (types_match_const_cast_only(ira, prev_type, cur_type, source_node).id == ConstCastResultIdOk) {
6565 continue;7353 continue;
6566 }7354 }
65677355
6568 if (types_match_const_cast_only(cur_type, prev_type)) {7356 if (types_match_const_cast_only(ira, cur_type, prev_type, source_node).id == ConstCastResultIdOk) {
6569 prev_inst = cur_inst;7357 prev_inst = cur_inst;
6570 continue;7358 continue;
6571 }7359 }
...@@ -6588,26 +7376,41 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -6588,26 +7376,41 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
6588 }7376 }
65897377
6590 if (prev_type->id == TypeTableEntryIdErrorUnion &&7378 if (prev_type->id == TypeTableEntryIdErrorUnion &&
6591 types_match_const_cast_only(prev_type->data.error.child_type, cur_type))7379 types_match_const_cast_only(ira, prev_type->data.error_union.payload_type, cur_type, source_node).id == ConstCastResultIdOk)
6592 {7380 {
6593 continue;7381 continue;
6594 }7382 }
65957383
6596 if (cur_type->id == TypeTableEntryIdErrorUnion &&7384 if (cur_type->id == TypeTableEntryIdErrorUnion &&
6597 types_match_const_cast_only(cur_type->data.error.child_type, prev_type))7385 types_match_const_cast_only(ira, cur_type->data.error_union.payload_type, prev_type, source_node).id == ConstCastResultIdOk)
6598 {7386 {
7387 if (err_set_type != nullptr) {
7388 TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
7389 if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) {
7390 return ira->codegen->builtin_types.entry_invalid;
7391 }
7392 if (type_is_global_error_set(cur_err_set_type) || type_is_global_error_set(err_set_type)) {
7393 err_set_type = ira->codegen->builtin_types.entry_global_error_set;
7394 prev_inst = cur_inst;
7395 continue;
7396 }
7397
7398 update_errors_helper(ira->codegen, &errors, &errors_count);
7399
7400 err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_err_set_type);
7401 }
6599 prev_inst = cur_inst;7402 prev_inst = cur_inst;
6600 continue;7403 continue;
6601 }7404 }
66027405
6603 if (prev_type->id == TypeTableEntryIdMaybe &&7406 if (prev_type->id == TypeTableEntryIdMaybe &&
6604 types_match_const_cast_only(prev_type->data.maybe.child_type, cur_type))7407 types_match_const_cast_only(ira, prev_type->data.maybe.child_type, cur_type, source_node).id == ConstCastResultIdOk)
6605 {7408 {
6606 continue;7409 continue;
6607 }7410 }
66087411
6609 if (cur_type->id == TypeTableEntryIdMaybe &&7412 if (cur_type->id == TypeTableEntryIdMaybe &&
6610 types_match_const_cast_only(cur_type->data.maybe.child_type, prev_type))7413 types_match_const_cast_only(ira, cur_type->data.maybe.child_type, prev_type, source_node).id == ConstCastResultIdOk)
6611 {7414 {
6612 prev_inst = cur_inst;7415 prev_inst = cur_inst;
6613 continue;7416 continue;
...@@ -6645,7 +7448,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -6645,7 +7448,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
66457448
6646 if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray &&7449 if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray &&
6647 cur_type->data.array.len != prev_type->data.array.len &&7450 cur_type->data.array.len != prev_type->data.array.len &&
6648 types_match_const_cast_only(cur_type->data.array.child_type, prev_type->data.array.child_type))7451 types_match_const_cast_only(ira, cur_type->data.array.child_type, prev_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
6649 {7452 {
6650 convert_to_const_slice = true;7453 convert_to_const_slice = true;
6651 prev_inst = cur_inst;7454 prev_inst = cur_inst;
...@@ -6654,7 +7457,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -6654,7 +7457,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
66547457
6655 if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray &&7458 if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray &&
6656 cur_type->data.array.len != prev_type->data.array.len &&7459 cur_type->data.array.len != prev_type->data.array.len &&
6657 types_match_const_cast_only(prev_type->data.array.child_type, cur_type->data.array.child_type))7460 types_match_const_cast_only(ira, prev_type->data.array.child_type, cur_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
6658 {7461 {
6659 convert_to_const_slice = true;7462 convert_to_const_slice = true;
6660 continue;7463 continue;
...@@ -6663,8 +7466,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -6663,8 +7466,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
6663 if (cur_type->id == TypeTableEntryIdArray && is_slice(prev_type) &&7466 if (cur_type->id == TypeTableEntryIdArray && is_slice(prev_type) &&
6664 (prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const ||7467 (prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const ||
6665 cur_type->data.array.len == 0) &&7468 cur_type->data.array.len == 0) &&
6666 types_match_const_cast_only(prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,7469 types_match_const_cast_only(ira, prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
6667 cur_type->data.array.child_type))7470 cur_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
6668 {7471 {
6669 convert_to_const_slice = false;7472 convert_to_const_slice = false;
6670 continue;7473 continue;
...@@ -6673,8 +7476,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -6673,8 +7476,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
6673 if (prev_type->id == TypeTableEntryIdArray && is_slice(cur_type) &&7476 if (prev_type->id == TypeTableEntryIdArray && is_slice(cur_type) &&
6674 (cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const ||7477 (cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const ||
6675 prev_type->data.array.len == 0) &&7478 prev_type->data.array.len == 0) &&
6676 types_match_const_cast_only(cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,7479 types_match_const_cast_only(ira, cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
6677 prev_type->data.array.child_type))7480 prev_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
6678 {7481 {
6679 prev_inst = cur_inst;7482 prev_inst = cur_inst;
6680 convert_to_const_slice = false;7483 convert_to_const_slice = false;
...@@ -6714,30 +7517,37 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -6714,30 +7517,37 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
67147517
6715 return ira->codegen->builtin_types.entry_invalid;7518 return ira->codegen->builtin_types.entry_invalid;
6716 }7519 }
7520
7521 free(errors);
7522
6717 if (convert_to_const_slice) {7523 if (convert_to_const_slice) {
6718 assert(prev_inst->value.type->id == TypeTableEntryIdArray);7524 assert(prev_inst->value.type->id == TypeTableEntryIdArray);
6719 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, prev_inst->value.type->data.array.child_type, true);7525 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, prev_inst->value.type->data.array.child_type, true);
6720 TypeTableEntry *slice_type = get_slice_type(ira->codegen, ptr_type);7526 TypeTableEntry *slice_type = get_slice_type(ira->codegen, ptr_type);
6721 if (any_are_pure_error) {7527 if (err_set_type != nullptr) {
6722 return get_error_type(ira->codegen, slice_type);7528 return get_error_union_type(ira->codegen, err_set_type, slice_type);
6723 } else {7529 } else {
6724 return slice_type;7530 return slice_type;
6725 }7531 }
6726 } else if (any_are_pure_error && prev_inst->value.type->id != TypeTableEntryIdPureError) {7532 } else if (err_set_type != nullptr) {
6727 if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||7533 if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) {
6728 prev_inst->value.type->id == TypeTableEntryIdNumLitFloat)7534 return err_set_type;
6729 {
6730 ir_add_error_node(ira, source_node,
6731 buf_sprintf("unable to make error union out of number literal"));
6732 return ira->codegen->builtin_types.entry_invalid;
6733 } else if (prev_inst->value.type->id == TypeTableEntryIdNullLit) {
6734 ir_add_error_node(ira, source_node,
6735 buf_sprintf("unable to make error union out of null literal"));
6736 return ira->codegen->builtin_types.entry_invalid;
6737 } else if (prev_inst->value.type->id == TypeTableEntryIdErrorUnion) {
6738 return prev_inst->value.type;
6739 } else {7535 } else {
6740 return get_error_type(ira->codegen, prev_inst->value.type);7536 if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||
7537 prev_inst->value.type->id == TypeTableEntryIdNumLitFloat)
7538 {
7539 ir_add_error_node(ira, source_node,
7540 buf_sprintf("unable to make error union out of number literal"));
7541 return ira->codegen->builtin_types.entry_invalid;
7542 } else if (prev_inst->value.type->id == TypeTableEntryIdNullLit) {
7543 ir_add_error_node(ira, source_node,
7544 buf_sprintf("unable to make error union out of null literal"));
7545 return ira->codegen->builtin_types.entry_invalid;
7546 } else if (prev_inst->value.type->id == TypeTableEntryIdErrorUnion) {
7547 return get_error_union_type(ira->codegen, err_set_type, prev_inst->value.type->data.error_union.payload_type);
7548 } else {
7549 return get_error_union_type(ira->codegen, err_set_type, prev_inst->value.type);
7550 }
6741 }7551 }
6742 } else if (any_are_null && prev_inst->value.type->id != TypeTableEntryIdNullLit) {7552 } else if (any_are_null && prev_inst->value.type->id != TypeTableEntryIdNullLit) {
6743 if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||7553 if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||
...@@ -6783,6 +7593,8 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,...@@ -6783,6 +7593,8 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
6783 switch (cast_op) {7593 switch (cast_op) {
6784 case CastOpNoCast:7594 case CastOpNoCast:
6785 zig_unreachable();7595 zig_unreachable();
7596 case CastOpErrSet:
7597 zig_panic("TODO");
6786 case CastOpNoop:7598 case CastOpNoop:
6787 {7599 {
6788 copy_const_val(const_val, other_val, other_val->special == ConstValSpecialStatic);7600 copy_const_val(const_val, other_val, other_val->special == ConstValSpecialStatic);
...@@ -7213,7 +8025,7 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction...@@ -7213,7 +8025,7 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction
7213 assert(wanted_type->id == TypeTableEntryIdErrorUnion);8025 assert(wanted_type->id == TypeTableEntryIdErrorUnion);
72148026
7215 if (instr_is_comptime(value)) {8027 if (instr_is_comptime(value)) {
7216 TypeTableEntry *payload_type = wanted_type->data.error.child_type;8028 TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type;
7217 IrInstruction *casted_payload = ir_implicit_cast(ira, value, payload_type);8029 IrInstruction *casted_payload = ir_implicit_cast(ira, value, payload_type);
7218 if (type_is_invalid(casted_payload->value.type))8030 if (type_is_invalid(casted_payload->value.type))
7219 return ira->codegen->invalid_instruction;8031 return ira->codegen->invalid_instruction;
...@@ -7238,19 +8050,64 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction...@@ -7238,19 +8050,64 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction
7238 return result;8050 return result;
7239}8051}
72408052
7241static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {8053static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
7242 assert(wanted_type->id == TypeTableEntryIdErrorUnion);8054 TypeTableEntry *wanted_type)
8055{
8056 assert(value->value.type->id == TypeTableEntryIdErrorSet);
8057 assert(wanted_type->id == TypeTableEntryIdErrorSet);
72438058
7244 if (instr_is_comptime(value)) {8059 if (instr_is_comptime(value)) {
7245 ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);8060 ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
7246 if (!val)8061 if (!val)
7247 return ira->codegen->invalid_instruction;8062 return ira->codegen->invalid_instruction;
72488063
8064 if (!resolve_inferred_error_set(ira, wanted_type, source_instr->source_node)) {
8065 return ira->codegen->invalid_instruction;
8066 }
8067 if (!type_is_global_error_set(wanted_type)) {
8068 bool subset = false;
8069 for (uint32_t i = 0, count = wanted_type->data.error_set.err_count; i < count; i += 1) {
8070 if (wanted_type->data.error_set.errors[i]->value == val->data.x_err_set->value) {
8071 subset = true;
8072 break;
8073 }
8074 }
8075 if (!subset) {
8076 ir_add_error(ira, source_instr,
8077 buf_sprintf("error.%s not a member of error set '%s'",
8078 buf_ptr(&val->data.x_err_set->name), buf_ptr(&wanted_type->name)));
8079 return ira->codegen->invalid_instruction;
8080 }
8081 }
8082
7249 IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,8083 IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
7250 source_instr->scope, source_instr->source_node);8084 source_instr->scope, source_instr->source_node);
7251 const_instruction->base.value.type = wanted_type;8085 const_instruction->base.value.type = wanted_type;
7252 const_instruction->base.value.special = ConstValSpecialStatic;8086 const_instruction->base.value.special = ConstValSpecialStatic;
7253 const_instruction->base.value.data.x_err_union.err = val->data.x_pure_err;8087 const_instruction->base.value.data.x_err_set = val->data.x_err_set;
8088 return &const_instruction->base;
8089 }
8090
8091 IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, CastOpErrSet);
8092 result->value.type = wanted_type;
8093 return result;
8094}
8095
8096static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {
8097 assert(wanted_type->id == TypeTableEntryIdErrorUnion);
8098
8099 IrInstruction *casted_value = ir_implicit_cast(ira, value, wanted_type->data.error_union.err_set_type);
8100
8101 if (instr_is_comptime(casted_value)) {
8102 ConstExprValue *val = ir_resolve_const(ira, casted_value, UndefBad);
8103 if (!val)
8104 return ira->codegen->invalid_instruction;
8105
8106 IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
8107 source_instr->scope, source_instr->source_node);
8108 const_instruction->base.value.type = wanted_type;
8109 const_instruction->base.value.special = ConstValSpecialStatic;
8110 const_instruction->base.value.data.x_err_union.err = val->data.x_err_set;
7254 const_instruction->base.value.data.x_err_union.payload = nullptr;8111 const_instruction->base.value.data.x_err_union.payload = nullptr;
7255 return &const_instruction->base;8112 return &const_instruction->base;
7256 }8113 }
...@@ -7630,36 +8487,68 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction...@@ -7630,36 +8487,68 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction
7630 return result;8487 return result;
7631}8488}
76328489
7633static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target) {8490static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target,
8491 TypeTableEntry *wanted_type)
8492{
7634 assert(target->value.type->id == TypeTableEntryIdInt);8493 assert(target->value.type->id == TypeTableEntryIdInt);
7635 assert(!target->value.type->data.integral.is_signed);8494 assert(!target->value.type->data.integral.is_signed);
8495 assert(wanted_type->id == TypeTableEntryIdErrorSet);
76368496
7637 if (instr_is_comptime(target)) {8497 if (instr_is_comptime(target)) {
7638 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);8498 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
7639 if (!val)8499 if (!val)
7640 return ira->codegen->invalid_instruction;8500 return ira->codegen->invalid_instruction;
76418501
7642 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,8502 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
7643 source_instr->source_node, ira->codegen->builtin_types.entry_pure_error);8503 source_instr->source_node, wanted_type);
8504
8505 if (!resolve_inferred_error_set(ira, wanted_type, source_instr->source_node)) {
8506 return ira->codegen->invalid_instruction;
8507 }
8508
8509 if (type_is_global_error_set(wanted_type)) {
8510 BigInt err_count;
8511 bigint_init_unsigned(&err_count, ira->codegen->errors_by_index.length);
8512
8513 if (bigint_cmp_zero(&val->data.x_bigint) == CmpEQ || bigint_cmp(&val->data.x_bigint, &err_count) != CmpLT) {
8514 Buf *val_buf = buf_alloc();
8515 bigint_append_buf(val_buf, &val->data.x_bigint, 10);
8516 ir_add_error(ira, source_instr,
8517 buf_sprintf("integer value %s represents no error", buf_ptr(val_buf)));
8518 return ira->codegen->invalid_instruction;
8519 }
8520
8521 size_t index = bigint_as_unsigned(&val->data.x_bigint);
8522 result->value.data.x_err_set = ira->codegen->errors_by_index.at(index);
8523 return result;
8524 } else {
8525 ErrorTableEntry *err = nullptr;
8526 BigInt err_int;
8527
8528 for (uint32_t i = 0, count = wanted_type->data.error_set.err_count; i < count; i += 1) {
8529 ErrorTableEntry *this_err = wanted_type->data.error_set.errors[i];
8530 bigint_init_unsigned(&err_int, this_err->value);
8531 if (bigint_cmp(&val->data.x_bigint, &err_int) == CmpEQ) {
8532 err = this_err;
8533 break;
8534 }
8535 }
76448536
7645 BigInt err_count;8537 if (err == nullptr) {
7646 bigint_init_unsigned(&err_count, ira->codegen->error_decls.length);8538 Buf *val_buf = buf_alloc();
7647 if (bigint_cmp_zero(&val->data.x_bigint) == CmpEQ || bigint_cmp(&val->data.x_bigint, &err_count) != CmpLT) {8539 bigint_append_buf(val_buf, &val->data.x_bigint, 10);
7648 Buf *val_buf = buf_alloc();8540 ir_add_error(ira, source_instr,
7649 bigint_append_buf(val_buf, &val->data.x_bigint, 10);8541 buf_sprintf("integer value %s represents no error in '%s'", buf_ptr(val_buf), buf_ptr(&wanted_type->name)));
7650 ir_add_error(ira, source_instr,8542 return ira->codegen->invalid_instruction;
7651 buf_sprintf("integer value %s represents no error", buf_ptr(val_buf)));8543 }
7652 return ira->codegen->invalid_instruction;
7653 }
76548544
7655 size_t index = bigint_as_unsigned(&val->data.x_bigint);8545 result->value.data.x_err_set = err;
7656 AstNode *error_decl_node = ira->codegen->error_decls.at(index);8546 return result;
7657 result->value.data.x_pure_err = error_decl_node->data.error_value_decl.err;8547 }
7658 return result;
7659 }8548 }
76608549
7661 IrInstruction *result = ir_build_int_to_err(&ira->new_irb, source_instr->scope, source_instr->source_node, target);8550 IrInstruction *result = ir_build_int_to_err(&ira->new_irb, source_instr->scope, source_instr->source_node, target);
7662 result->value.type = ira->codegen->builtin_types.entry_pure_error;8551 result->value.type = wanted_type;
7663 return result;8552 return result;
7664}8553}
76658554
...@@ -7681,8 +8570,8 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc...@@ -7681,8 +8570,8 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
7681 ErrorTableEntry *err;8570 ErrorTableEntry *err;
7682 if (err_type->id == TypeTableEntryIdErrorUnion) {8571 if (err_type->id == TypeTableEntryIdErrorUnion) {
7683 err = val->data.x_err_union.err;8572 err = val->data.x_err_union.err;
7684 } else if (err_type->id == TypeTableEntryIdPureError) {8573 } else if (err_type->id == TypeTableEntryIdErrorSet) {
7685 err = val->data.x_pure_err;8574 err = val->data.x_err_set;
7686 } else {8575 } else {
7687 zig_unreachable();8576 zig_unreachable();
7688 }8577 }
...@@ -7702,8 +8591,36 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc...@@ -7702,8 +8591,36 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
7702 return result;8591 return result;
7703 }8592 }
77048593
8594 TypeTableEntry *err_set_type;
8595 if (err_type->id == TypeTableEntryIdErrorUnion) {
8596 err_set_type = err_type->data.error_union.err_set_type;
8597 } else if (err_type->id == TypeTableEntryIdErrorSet) {
8598 err_set_type = err_type;
8599 } else {
8600 zig_unreachable();
8601 }
8602 if (!type_is_global_error_set(err_set_type)) {
8603 if (!resolve_inferred_error_set(ira, err_set_type, source_instr->source_node)) {
8604 return ira->codegen->invalid_instruction;
8605 }
8606 if (err_set_type->data.error_set.err_count == 0) {
8607 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
8608 source_instr->source_node, wanted_type);
8609 result->value.type = wanted_type;
8610 bigint_init_unsigned(&result->value.data.x_bigint, 0);
8611 return result;
8612 } else if (err_set_type->data.error_set.err_count == 1) {
8613 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
8614 source_instr->source_node, wanted_type);
8615 result->value.type = wanted_type;
8616 ErrorTableEntry *err = err_set_type->data.error_set.errors[0];
8617 bigint_init_unsigned(&result->value.data.x_bigint, err->value);
8618 return result;
8619 }
8620 }
8621
7705 BigInt bn;8622 BigInt bn;
7706 bigint_init_unsigned(&bn, ira->codegen->error_decls.length);8623 bigint_init_unsigned(&bn, ira->codegen->errors_by_index.length);
7707 if (!bigint_fits_in_bits(&bn, wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) {8624 if (!bigint_fits_in_bits(&bn, wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) {
7708 ir_add_error_node(ira, source_instr->source_node,8625 ir_add_error_node(ira, source_instr->source_node,
7709 buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name)));8626 buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name)));
...@@ -7719,6 +8636,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -7719,6 +8636,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
7719 TypeTableEntry *wanted_type, IrInstruction *value)8636 TypeTableEntry *wanted_type, IrInstruction *value)
7720{8637{
7721 TypeTableEntry *actual_type = value->value.type;8638 TypeTableEntry *actual_type = value->value.type;
8639 AstNode *source_node = source_instr->source_node;
77228640
7723 if (type_is_invalid(wanted_type) || type_is_invalid(actual_type)) {8641 if (type_is_invalid(wanted_type) || type_is_invalid(actual_type)) {
7724 return ira->codegen->invalid_instruction;8642 return ira->codegen->invalid_instruction;
...@@ -7728,7 +8646,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -7728,7 +8646,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
7728 return value;8646 return value;
77298647
7730 // explicit match or non-const to const8648 // explicit match or non-const to const
7731 if (types_match_const_cast_only(wanted_type, actual_type)) {8649 if (types_match_const_cast_only(ira, wanted_type, actual_type, source_node).id == ConstCastResultIdOk) {
7732 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);8650 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
7733 }8651 }
77348652
...@@ -7748,6 +8666,13 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -7748,6 +8666,13 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
7748 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);8666 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
7749 }8667 }
77508668
8669 // explicit error set cast
8670 if (wanted_type->id == TypeTableEntryIdErrorSet &&
8671 actual_type->id == TypeTableEntryIdErrorSet)
8672 {
8673 return ir_analyze_err_set_cast(ira, source_instr, value, wanted_type);
8674 }
8675
7751 // explicit cast from int to float8676 // explicit cast from int to float
7752 if (wanted_type->id == TypeTableEntryIdFloat &&8677 if (wanted_type->id == TypeTableEntryIdFloat &&
7753 actual_type->id == TypeTableEntryIdInt)8678 actual_type->id == TypeTableEntryIdInt)
...@@ -7767,7 +8692,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -7767,7 +8692,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
7767 TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;8692 TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
7768 assert(ptr_type->id == TypeTableEntryIdPointer);8693 assert(ptr_type->id == TypeTableEntryIdPointer);
7769 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&8694 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
7770 types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type))8695 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
7771 {8696 {
7772 return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);8697 return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
7773 }8698 }
...@@ -7785,7 +8710,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -7785,7 +8710,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
7785 TypeTableEntry *array_type = actual_type->data.pointer.child_type;8710 TypeTableEntry *array_type = actual_type->data.pointer.child_type;
77868711
7787 if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&8712 if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
7788 types_match_const_cast_only(ptr_type->data.pointer.child_type, array_type->data.array.child_type))8713 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
7789 {8714 {
7790 return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);8715 return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
7791 }8716 }
...@@ -7801,7 +8726,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -7801,7 +8726,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
7801 wanted_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;8726 wanted_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;
7802 assert(ptr_type->id == TypeTableEntryIdPointer);8727 assert(ptr_type->id == TypeTableEntryIdPointer);
7803 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&8728 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
7804 types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type))8729 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
7805 {8730 {
7806 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);8731 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);
7807 if (type_is_invalid(cast1->value.type))8732 if (type_is_invalid(cast1->value.type))
...@@ -7824,7 +8749,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -7824,7 +8749,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
7824 wanted_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;8749 wanted_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;
7825 assert(ptr_type->id == TypeTableEntryIdPointer);8750 assert(ptr_type->id == TypeTableEntryIdPointer);
7826 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&8751 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
7827 types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type))8752 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
7828 {8753 {
7829 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value);8754 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value);
7830 if (type_is_invalid(cast1->value.type))8755 if (type_is_invalid(cast1->value.type))
...@@ -7886,7 +8811,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -7886,7 +8811,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
78868811
7887 // explicit cast from child type of maybe type to maybe type8812 // explicit cast from child type of maybe type to maybe type
7888 if (wanted_type->id == TypeTableEntryIdMaybe) {8813 if (wanted_type->id == TypeTableEntryIdMaybe) {
7889 if (types_match_const_cast_only(wanted_type->data.maybe.child_type, actual_type)) {8814 if (types_match_const_cast_only(ira, wanted_type->data.maybe.child_type, actual_type, source_node).id == ConstCastResultIdOk) {
7890 return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);8815 return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
7891 } else if (actual_type->id == TypeTableEntryIdNumLitInt ||8816 } else if (actual_type->id == TypeTableEntryIdNumLitInt ||
7892 actual_type->id == TypeTableEntryIdNumLitFloat)8817 actual_type->id == TypeTableEntryIdNumLitFloat)
...@@ -7908,12 +8833,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -7908,12 +8833,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
79088833
7909 // explicit cast from child type of error type to error type8834 // explicit cast from child type of error type to error type
7910 if (wanted_type->id == TypeTableEntryIdErrorUnion) {8835 if (wanted_type->id == TypeTableEntryIdErrorUnion) {
7911 if (types_match_const_cast_only(wanted_type->data.error.child_type, actual_type)) {8836 if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type, source_node).id == ConstCastResultIdOk) {
7912 return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);8837 return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
7913 } else if (actual_type->id == TypeTableEntryIdNumLitInt ||8838 } else if (actual_type->id == TypeTableEntryIdNumLitInt ||
7914 actual_type->id == TypeTableEntryIdNumLitFloat)8839 actual_type->id == TypeTableEntryIdNumLitFloat)
7915 {8840 {
7916 if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error.child_type, true)) {8841 if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error_union.payload_type, true)) {
7917 return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);8842 return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
7918 } else {8843 } else {
7919 return ira->codegen->invalid_instruction;8844 return ira->codegen->invalid_instruction;
...@@ -7923,16 +8848,16 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -7923,16 +8848,16 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
79238848
7924 // explicit cast from [N]T to %[]const T8849 // explicit cast from [N]T to %[]const T
7925 if (wanted_type->id == TypeTableEntryIdErrorUnion &&8850 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
7926 is_slice(wanted_type->data.error.child_type) &&8851 is_slice(wanted_type->data.error_union.payload_type) &&
7927 actual_type->id == TypeTableEntryIdArray)8852 actual_type->id == TypeTableEntryIdArray)
7928 {8853 {
7929 TypeTableEntry *ptr_type =8854 TypeTableEntry *ptr_type =
7930 wanted_type->data.error.child_type->data.structure.fields[slice_ptr_index].type_entry;8855 wanted_type->data.error_union.payload_type->data.structure.fields[slice_ptr_index].type_entry;
7931 assert(ptr_type->id == TypeTableEntryIdPointer);8856 assert(ptr_type->id == TypeTableEntryIdPointer);
7932 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&8857 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
7933 types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type))8858 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
7934 {8859 {
7935 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error.child_type, value);8860 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value);
7936 if (type_is_invalid(cast1->value.type))8861 if (type_is_invalid(cast1->value.type))
7937 return ira->codegen->invalid_instruction;8862 return ira->codegen->invalid_instruction;
79388863
...@@ -7944,25 +8869,25 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -7944,25 +8869,25 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
7944 }8869 }
7945 }8870 }
79468871
7947 // explicit cast from pure error to error union type8872 // explicit cast from error set to error union type
7948 if (wanted_type->id == TypeTableEntryIdErrorUnion &&8873 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
7949 actual_type->id == TypeTableEntryIdPureError)8874 actual_type->id == TypeTableEntryIdErrorSet)
7950 {8875 {
7951 return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type);8876 return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type);
7952 }8877 }
79538878
7954 // explicit cast from T to %?T8879 // explicit cast from T to %?T
7955 if (wanted_type->id == TypeTableEntryIdErrorUnion &&8880 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
7956 wanted_type->data.error.child_type->id == TypeTableEntryIdMaybe &&8881 wanted_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe &&
7957 actual_type->id != TypeTableEntryIdMaybe)8882 actual_type->id != TypeTableEntryIdMaybe)
7958 {8883 {
7959 TypeTableEntry *wanted_child_type = wanted_type->data.error.child_type->data.maybe.child_type;8884 TypeTableEntry *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type;
7960 if (types_match_const_cast_only(wanted_child_type, actual_type) ||8885 if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node).id == ConstCastResultIdOk ||
7961 actual_type->id == TypeTableEntryIdNullLit ||8886 actual_type->id == TypeTableEntryIdNullLit ||
7962 actual_type->id == TypeTableEntryIdNumLitInt ||8887 actual_type->id == TypeTableEntryIdNumLitInt ||
7963 actual_type->id == TypeTableEntryIdNumLitFloat)8888 actual_type->id == TypeTableEntryIdNumLitFloat)
7964 {8889 {
7965 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error.child_type, value);8890 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value);
7966 if (type_is_invalid(cast1->value.type))8891 if (type_is_invalid(cast1->value.type))
7967 return ira->codegen->invalid_instruction;8892 return ira->codegen->invalid_instruction;
79688893
...@@ -8031,21 +8956,19 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -8031,21 +8956,19 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
8031 return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type);8956 return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type);
8032 }8957 }
80338958
8034 // explicit cast from %void to integer type which can fit it8959 // explicit cast from T!void to integer type which can fit it
8035 bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion &&8960 bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion &&
8036 !type_has_bits(actual_type->data.error.child_type);8961 !type_has_bits(actual_type->data.error_union.payload_type);
8037 bool actual_type_is_pure_err = actual_type->id == TypeTableEntryIdPureError;8962 bool actual_type_is_err_set = actual_type->id == TypeTableEntryIdErrorSet;
8038 if ((actual_type_is_void_err || actual_type_is_pure_err) &&8963 if ((actual_type_is_void_err || actual_type_is_err_set) && wanted_type->id == TypeTableEntryIdInt) {
8039 wanted_type->id == TypeTableEntryIdInt)
8040 {
8041 return ir_analyze_err_to_int(ira, source_instr, value, wanted_type);8964 return ir_analyze_err_to_int(ira, source_instr, value, wanted_type);
8042 }8965 }
80438966
8044 // explicit cast from integer to pure error8967 // explicit cast from integer to error set
8045 if (wanted_type->id == TypeTableEntryIdPureError && actual_type->id == TypeTableEntryIdInt &&8968 if (wanted_type->id == TypeTableEntryIdErrorSet && actual_type->id == TypeTableEntryIdInt &&
8046 !actual_type->data.integral.is_signed)8969 !actual_type->data.integral.is_signed)
8047 {8970 {
8048 return ir_analyze_int_to_err(ira, source_instr, value);8971 return ir_analyze_int_to_err(ira, source_instr, value, wanted_type);
8049 }8972 }
80508973
8051 // explicit cast from integer to enum type with no payload8974 // explicit cast from integer to enum type with no payload
...@@ -8109,7 +9032,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -8109,7 +9032,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
8109 // explicit cast from something to const pointer of it9032 // explicit cast from something to const pointer of it
8110 if (!type_requires_comptime(actual_type)) {9033 if (!type_requires_comptime(actual_type)) {
8111 TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);9034 TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);
8112 if (types_match_const_cast_only(wanted_type, const_ptr_actual)) {9035 if (types_match_const_cast_only(ira, wanted_type, const_ptr_actual, source_node).id == ConstCastResultIdOk) {
8113 return ir_analyze_cast_ref(ira, source_instr, value, wanted_type);9036 return ir_analyze_cast_ref(ira, source_instr, value, wanted_type);
8114 }9037 }
8115 }9038 }
...@@ -8471,6 +9394,7 @@ static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) {...@@ -8471,6 +9394,7 @@ static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) {
8471static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {9394static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
8472 IrInstruction *op1 = bin_op_instruction->op1->other;9395 IrInstruction *op1 = bin_op_instruction->op1->other;
8473 IrInstruction *op2 = bin_op_instruction->op2->other;9396 IrInstruction *op2 = bin_op_instruction->op2->other;
9397 AstNode *source_node = bin_op_instruction->base.source_node;
84749398
8475 IrBinOp op_id = bin_op_instruction->op_id;9399 IrBinOp op_id = bin_op_instruction->op_id;
8476 bool is_equality_cmp = (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq);9400 bool is_equality_cmp = (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq);
...@@ -8503,7 +9427,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp...@@ -8503,7 +9427,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
8503 }9427 }
85049428
8505 IrInstruction *is_non_null = ir_build_test_nonnull(&ira->new_irb, bin_op_instruction->base.scope,9429 IrInstruction *is_non_null = ir_build_test_nonnull(&ira->new_irb, bin_op_instruction->base.scope,
8506 bin_op_instruction->base.source_node, maybe_op);9430 source_node, maybe_op);
8507 is_non_null->value.type = ira->codegen->builtin_types.entry_bool;9431 is_non_null->value.type = ira->codegen->builtin_types.entry_bool;
85089432
8509 if (op_id == IrBinOpCmpEq) {9433 if (op_id == IrBinOpCmpEq) {
...@@ -8514,8 +9438,88 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp...@@ -8514,8 +9438,88 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
8514 return ira->codegen->builtin_types.entry_bool;9438 return ira->codegen->builtin_types.entry_bool;
8515 }9439 }
85169440
9441 if (op1->value.type->id == TypeTableEntryIdErrorSet && op2->value.type->id == TypeTableEntryIdErrorSet) {
9442 if (!is_equality_cmp) {
9443 ir_add_error_node(ira, source_node, buf_sprintf("operator not allowed for errors"));
9444 return ira->codegen->builtin_types.entry_invalid;
9445 }
9446 TypeTableEntry *intersect_type = get_error_set_intersection(ira, op1->value.type, op2->value.type, source_node);
9447 if (type_is_invalid(intersect_type)) {
9448 return ira->codegen->builtin_types.entry_invalid;
9449 }
9450
9451 if (!resolve_inferred_error_set(ira, intersect_type, source_node)) {
9452 return ira->codegen->builtin_types.entry_invalid;
9453 }
9454
9455 // exception if one of the operators has the type of the empty error set, we allow the comparison
9456 // (and make it comptime known)
9457 // this is a function which is evaluated at comptime and returns an inferred error set will have an empty
9458 // error set.
9459 if (op1->value.type->data.error_set.err_count == 0 || op2->value.type->data.error_set.err_count == 0) {
9460 bool are_equal = false;
9461 bool answer;
9462 if (op_id == IrBinOpCmpEq) {
9463 answer = are_equal;
9464 } else if (op_id == IrBinOpCmpNotEq) {
9465 answer = !are_equal;
9466 } else {
9467 zig_unreachable();
9468 }
9469 ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base);
9470 out_val->data.x_bool = answer;
9471 return ira->codegen->builtin_types.entry_bool;
9472 }
9473
9474 if (!type_is_global_error_set(intersect_type)) {
9475 if (intersect_type->data.error_set.err_count == 0) {
9476 ir_add_error_node(ira, source_node,
9477 buf_sprintf("error sets '%s' and '%s' have no common errors",
9478 buf_ptr(&op1->value.type->name), buf_ptr(&op2->value.type->name)));
9479 return ira->codegen->builtin_types.entry_invalid;
9480 }
9481 if (op1->value.type->data.error_set.err_count == 1 && op2->value.type->data.error_set.err_count == 1) {
9482 bool are_equal = true;
9483 bool answer;
9484 if (op_id == IrBinOpCmpEq) {
9485 answer = are_equal;
9486 } else if (op_id == IrBinOpCmpNotEq) {
9487 answer = !are_equal;
9488 } else {
9489 zig_unreachable();
9490 }
9491 ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base);
9492 out_val->data.x_bool = answer;
9493 return ira->codegen->builtin_types.entry_bool;
9494 }
9495 }
9496
9497 ConstExprValue *op1_val = &op1->value;
9498 ConstExprValue *op2_val = &op2->value;
9499 if (value_is_comptime(op1_val) && value_is_comptime(op2_val)) {
9500 bool answer;
9501 bool are_equal = op1_val->data.x_err_set->value == op2_val->data.x_err_set->value;
9502 if (op_id == IrBinOpCmpEq) {
9503 answer = are_equal;
9504 } else if (op_id == IrBinOpCmpNotEq) {
9505 answer = !are_equal;
9506 } else {
9507 zig_unreachable();
9508 }
9509
9510 ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base);
9511 out_val->data.x_bool = answer;
9512 return ira->codegen->builtin_types.entry_bool;
9513 }
9514
9515 ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, op_id,
9516 op1, op2, bin_op_instruction->safety_check_on);
9517
9518 return ira->codegen->builtin_types.entry_bool;
9519 }
9520
8517 IrInstruction *instructions[] = {op1, op2};9521 IrInstruction *instructions[] = {op1, op2};
8518 TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, bin_op_instruction->base.source_node, instructions, 2);9522 TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, source_node, instructions, 2);
8519 if (type_is_invalid(resolved_type))9523 if (type_is_invalid(resolved_type))
8520 return resolved_type;9524 return resolved_type;
8521 type_ensure_zero_bits_known(ira->codegen, resolved_type);9525 type_ensure_zero_bits_known(ira->codegen, resolved_type);
...@@ -8523,7 +9527,6 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp...@@ -8523,7 +9527,6 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
8523 return resolved_type;9527 return resolved_type;
85249528
85259529
8526 AstNode *source_node = bin_op_instruction->base.source_node;
8527 switch (resolved_type->id) {9530 switch (resolved_type->id) {
8528 case TypeTableEntryIdInvalid:9531 case TypeTableEntryIdInvalid:
8529 zig_unreachable(); // handled above9532 zig_unreachable(); // handled above
...@@ -8538,7 +9541,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp...@@ -8538,7 +9541,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
8538 case TypeTableEntryIdMetaType:9541 case TypeTableEntryIdMetaType:
8539 case TypeTableEntryIdVoid:9542 case TypeTableEntryIdVoid:
8540 case TypeTableEntryIdPointer:9543 case TypeTableEntryIdPointer:
8541 case TypeTableEntryIdPureError:9544 case TypeTableEntryIdErrorSet:
8542 case TypeTableEntryIdFn:9545 case TypeTableEntryIdFn:
8543 case TypeTableEntryIdOpaque:9546 case TypeTableEntryIdOpaque:
8544 case TypeTableEntryIdNamespace:9547 case TypeTableEntryIdNamespace:
...@@ -8692,6 +9695,7 @@ static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val,...@@ -8692,6 +9695,7 @@ static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val,
8692 case IrBinOpArrayCat:9695 case IrBinOpArrayCat:
8693 case IrBinOpArrayMult:9696 case IrBinOpArrayMult:
8694 case IrBinOpRemUnspecified:9697 case IrBinOpRemUnspecified:
9698 case IrBinOpMergeErrorSets:
8695 zig_unreachable();9699 zig_unreachable();
8696 case IrBinOpBinOr:9700 case IrBinOpBinOr:
8697 assert(is_int);9701 assert(is_int);
...@@ -9264,6 +10268,46 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp...@@ -9264,6 +10268,46 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp
9264 return get_array_type(ira->codegen, child_type, new_array_len);10268 return get_array_type(ira->codegen, child_type, new_array_len);
9265}10269}
926610270
10271static TypeTableEntry *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstructionBinOp *instruction) {
10272 TypeTableEntry *op1_type = ir_resolve_type(ira, instruction->op1->other);
10273 if (type_is_invalid(op1_type))
10274 return ira->codegen->builtin_types.entry_invalid;
10275
10276 TypeTableEntry *op2_type = ir_resolve_type(ira, instruction->op2->other);
10277 if (type_is_invalid(op2_type))
10278 return ira->codegen->builtin_types.entry_invalid;
10279
10280 if (type_is_global_error_set(op1_type) ||
10281 type_is_global_error_set(op2_type))
10282 {
10283 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
10284 out_val->data.x_type = ira->codegen->builtin_types.entry_global_error_set;
10285 return ira->codegen->builtin_types.entry_type;
10286 }
10287
10288 if (!resolve_inferred_error_set(ira, op1_type, instruction->op1->other->source_node)) {
10289 return ira->codegen->builtin_types.entry_invalid;
10290 }
10291
10292 if (!resolve_inferred_error_set(ira, op2_type, instruction->op2->other->source_node)) {
10293 return ira->codegen->builtin_types.entry_invalid;
10294 }
10295
10296 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
10297 for (uint32_t i = 0, count = op1_type->data.error_set.err_count; i < count; i += 1) {
10298 ErrorTableEntry *error_entry = op1_type->data.error_set.errors[i];
10299 assert(errors[error_entry->value] == nullptr);
10300 errors[error_entry->value] = error_entry;
10301 }
10302 TypeTableEntry *result_type = get_error_set_union(ira->codegen, errors, op1_type, op2_type);
10303 free(errors);
10304
10305
10306 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
10307 out_val->data.x_type = result_type;
10308 return ira->codegen->builtin_types.entry_type;
10309}
10310
9267static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {10311static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
9268 IrBinOp op_id = bin_op_instruction->op_id;10312 IrBinOp op_id = bin_op_instruction->op_id;
9269 switch (op_id) {10313 switch (op_id) {
...@@ -9305,6 +10349,8 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi...@@ -9305,6 +10349,8 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi
9305 return ir_analyze_array_cat(ira, bin_op_instruction);10349 return ir_analyze_array_cat(ira, bin_op_instruction);
9306 case IrBinOpArrayMult:10350 case IrBinOpArrayMult:
9307 return ir_analyze_array_mult(ira, bin_op_instruction);10351 return ir_analyze_array_mult(ira, bin_op_instruction);
10352 case IrBinOpMergeErrorSets:
10353 return ir_analyze_merge_error_sets(ira, bin_op_instruction);
9308 }10354 }
9309 zig_unreachable();10355 zig_unreachable();
9310}10356}
...@@ -9326,7 +10372,7 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) {...@@ -9326,7 +10372,7 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) {
9326 case TypeTableEntryIdInt:10372 case TypeTableEntryIdInt:
9327 case TypeTableEntryIdFloat:10373 case TypeTableEntryIdFloat:
9328 case TypeTableEntryIdVoid:10374 case TypeTableEntryIdVoid:
9329 case TypeTableEntryIdPureError:10375 case TypeTableEntryIdErrorSet:
9330 case TypeTableEntryIdFn:10376 case TypeTableEntryIdFn:
9331 return VarClassRequiredAny;10377 return VarClassRequiredAny;
9332 case TypeTableEntryIdNumLitFloat:10378 case TypeTableEntryIdNumLitFloat:
...@@ -9352,7 +10398,7 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) {...@@ -9352,7 +10398,7 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) {
9352 case TypeTableEntryIdMaybe:10398 case TypeTableEntryIdMaybe:
9353 return get_var_class_required(type_entry->data.maybe.child_type);10399 return get_var_class_required(type_entry->data.maybe.child_type);
9354 case TypeTableEntryIdErrorUnion:10400 case TypeTableEntryIdErrorUnion:
9355 return get_var_class_required(type_entry->data.error.child_type);10401 return get_var_class_required(type_entry->data.error_union.payload_type);
935610402
9357 case TypeTableEntryIdStruct:10403 case TypeTableEntryIdStruct:
9358 case TypeTableEntryIdEnum:10404 case TypeTableEntryIdEnum:
...@@ -9587,7 +10633,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi...@@ -9587,7 +10633,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
9587 case TypeTableEntryIdNullLit:10633 case TypeTableEntryIdNullLit:
9588 case TypeTableEntryIdMaybe:10634 case TypeTableEntryIdMaybe:
9589 case TypeTableEntryIdErrorUnion:10635 case TypeTableEntryIdErrorUnion:
9590 case TypeTableEntryIdPureError:10636 case TypeTableEntryIdErrorSet:
9591 case TypeTableEntryIdNamespace:10637 case TypeTableEntryIdNamespace:
9592 case TypeTableEntryIdBlock:10638 case TypeTableEntryIdBlock:
9593 case TypeTableEntryIdBoundFn:10639 case TypeTableEntryIdBoundFn:
...@@ -9610,7 +10656,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi...@@ -9610,7 +10656,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
9610 case TypeTableEntryIdNullLit:10656 case TypeTableEntryIdNullLit:
9611 case TypeTableEntryIdMaybe:10657 case TypeTableEntryIdMaybe:
9612 case TypeTableEntryIdErrorUnion:10658 case TypeTableEntryIdErrorUnion:
9613 case TypeTableEntryIdPureError:10659 case TypeTableEntryIdErrorSet:
9614 zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name));10660 zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name));
9615 case TypeTableEntryIdNamespace:10661 case TypeTableEntryIdNamespace:
9616 case TypeTableEntryIdBlock:10662 case TypeTableEntryIdBlock:
...@@ -9644,6 +10690,31 @@ static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,...@@ -9644,6 +10690,31 @@ static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
9644 return nullable_type;10690 return nullable_type;
9645}10691}
964610692
10693static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira,
10694 IrInstructionErrorUnion *instruction)
10695{
10696 TypeTableEntry *err_set_type = ir_resolve_type(ira, instruction->err_set->other);
10697 if (type_is_invalid(err_set_type))
10698 return ira->codegen->builtin_types.entry_invalid;
10699
10700 TypeTableEntry *payload_type = ir_resolve_type(ira, instruction->payload->other);
10701 if (type_is_invalid(payload_type))
10702 return ira->codegen->builtin_types.entry_invalid;
10703
10704 if (err_set_type->id != TypeTableEntryIdErrorSet) {
10705 ir_add_error(ira, instruction->err_set->other,
10706 buf_sprintf("expected error set type, found type '%s'",
10707 buf_ptr(&err_set_type->name)));
10708 return ira->codegen->builtin_types.entry_invalid;
10709 }
10710
10711 TypeTableEntry *result_type = get_error_union_type(ira->codegen, err_set_type, payload_type);
10712
10713 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
10714 out_val->data.x_type = result_type;
10715 return ira->codegen->builtin_types.entry_type;
10716}
10717
9647static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,10718static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
9648 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)10719 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)
9649{10720{
...@@ -9926,9 +10997,17 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -9926,9 +10997,17 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
9926 }10997 }
992710998
9928 AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;10999 AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
9929 TypeTableEntry *return_type = analyze_type_expr(ira->codegen, exec_scope, return_type_node);11000 TypeTableEntry *specified_return_type = analyze_type_expr(ira->codegen, exec_scope, return_type_node);
9930 if (type_is_invalid(return_type))11001 if (type_is_invalid(specified_return_type))
9931 return ira->codegen->builtin_types.entry_invalid;11002 return ira->codegen->builtin_types.entry_invalid;
11003 TypeTableEntry *return_type;
11004 TypeTableEntry *inferred_err_set_type = nullptr;
11005 if (fn_proto_node->data.fn_proto.auto_err_set) {
11006 inferred_err_set_type = get_auto_err_set_type(ira->codegen, fn_entry);
11007 return_type = get_error_union_type(ira->codegen, inferred_err_set_type, specified_return_type);
11008 } else {
11009 return_type = specified_return_type;
11010 }
993211011
9933 IrInstruction *result;11012 IrInstruction *result;
993411013
...@@ -9942,6 +11021,23 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -9942,6 +11021,23 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
9942 ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry,11021 ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry,
9943 nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec);11022 nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec);
994411023
11024 if (inferred_err_set_type != nullptr) {
11025 inferred_err_set_type->data.error_set.infer_fn = nullptr;
11026 if (result->value.type->id == TypeTableEntryIdErrorUnion) {
11027 if (result->value.data.x_err_union.err != nullptr) {
11028 inferred_err_set_type->data.error_set.err_count = 1;
11029 inferred_err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(1);
11030 inferred_err_set_type->data.error_set.errors[0] = result->value.data.x_err_union.err;
11031 }
11032 TypeTableEntry *fn_inferred_err_set_type = result->value.type->data.error_union.err_set_type;
11033 inferred_err_set_type->data.error_set.err_count = fn_inferred_err_set_type->data.error_set.err_count;
11034 inferred_err_set_type->data.error_set.errors = fn_inferred_err_set_type->data.error_set.errors;
11035 } else if (result->value.type->id == TypeTableEntryIdErrorSet) {
11036 inferred_err_set_type->data.error_set.err_count = result->value.type->data.error_set.err_count;
11037 inferred_err_set_type->data.error_set.errors = result->value.type->data.error_set.errors;
11038 }
11039 }
11040
9945 ira->codegen->memoized_fn_eval_table.put(exec_scope, result);11041 ira->codegen->memoized_fn_eval_table.put(exec_scope, result);
994611042
9947 if (type_is_invalid(result->value.type))11043 if (type_is_invalid(result->value.type))
...@@ -10092,12 +11188,17 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -10092,12 +11188,17 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1009211188
10093 {11189 {
10094 AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;11190 AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
10095 TypeTableEntry *return_type = analyze_type_expr(ira->codegen, impl_fn->child_scope, return_type_node);11191 TypeTableEntry *specified_return_type = analyze_type_expr(ira->codegen, impl_fn->child_scope, return_type_node);
10096 if (type_is_invalid(return_type))11192 if (type_is_invalid(specified_return_type))
10097 return ira->codegen->builtin_types.entry_invalid;11193 return ira->codegen->builtin_types.entry_invalid;
10098 inst_fn_type_id.return_type = return_type;11194 if (fn_proto_node->data.fn_proto.auto_err_set) {
11195 TypeTableEntry *inferred_err_set_type = get_auto_err_set_type(ira->codegen, impl_fn);
11196 inst_fn_type_id.return_type = get_error_union_type(ira->codegen, inferred_err_set_type, specified_return_type);
11197 } else {
11198 inst_fn_type_id.return_type = specified_return_type;
11199 }
1009911200
10100 if (type_requires_comptime(return_type)) {11201 if (type_requires_comptime(specified_return_type)) {
10101 // Throw out our work and call the function as if it were comptime.11202 // Throw out our work and call the function as if it were comptime.
10102 return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, FnInlineAuto);11203 return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, FnInlineAuto);
10103 }11204 }
...@@ -10128,7 +11229,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -10128,7 +11229,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
10128 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;11229 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
10129 ir_add_alloca(ira, new_call_instruction, return_type);11230 ir_add_alloca(ira, new_call_instruction, return_type);
1013011231
10131 if (return_type->id == TypeTableEntryIdPureError || return_type->id == TypeTableEntryIdErrorUnion) {11232 if (return_type->id == TypeTableEntryIdErrorSet || return_type->id == TypeTableEntryIdErrorUnion) {
10132 parent_fn_entry->calls_errorable_function = true;11233 parent_fn_entry->calls_errorable_function = true;
10133 }11234 }
1013411235
...@@ -10138,7 +11239,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -10138,7 +11239,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
10138 FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);11239 FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
10139 assert(fn_type_id->return_type != nullptr);11240 assert(fn_type_id->return_type != nullptr);
10140 assert(parent_fn_entry != nullptr);11241 assert(parent_fn_entry != nullptr);
10141 if (fn_type_id->return_type->id == TypeTableEntryIdPureError || fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) {11242 if (fn_type_id->return_type->id == TypeTableEntryIdErrorSet || fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) {
10142 parent_fn_entry->calls_errorable_function = true;11243 parent_fn_entry->calls_errorable_function = true;
10143 }11244 }
1014411245
...@@ -10257,58 +11358,6 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction...@@ -10257,58 +11358,6 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
10257 }11358 }
10258}11359}
1025911360
10260static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
10261 assert(un_op_instruction->op_id == IrUnOpError);
10262 IrInstruction *value = un_op_instruction->value->other;
10263
10264 TypeTableEntry *meta_type = ir_resolve_type(ira, value);
10265 if (type_is_invalid(meta_type))
10266 return ira->codegen->builtin_types.entry_invalid;
10267
10268
10269 switch (meta_type->id) {
10270 case TypeTableEntryIdInvalid: // handled above
10271 zig_unreachable();
10272
10273 case TypeTableEntryIdVoid:
10274 case TypeTableEntryIdBool:
10275 case TypeTableEntryIdInt:
10276 case TypeTableEntryIdFloat:
10277 case TypeTableEntryIdPointer:
10278 case TypeTableEntryIdArray:
10279 case TypeTableEntryIdStruct:
10280 case TypeTableEntryIdMaybe:
10281 case TypeTableEntryIdErrorUnion:
10282 case TypeTableEntryIdPureError:
10283 case TypeTableEntryIdEnum:
10284 case TypeTableEntryIdUnion:
10285 case TypeTableEntryIdFn:
10286 case TypeTableEntryIdBoundFn:
10287 {
10288 ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);
10289 TypeTableEntry *result_type = get_error_type(ira->codegen, meta_type);
10290 out_val->data.x_type = result_type;
10291 return ira->codegen->builtin_types.entry_type;
10292 }
10293 case TypeTableEntryIdMetaType:
10294 case TypeTableEntryIdNumLitFloat:
10295 case TypeTableEntryIdNumLitInt:
10296 case TypeTableEntryIdUndefLit:
10297 case TypeTableEntryIdNullLit:
10298 case TypeTableEntryIdNamespace:
10299 case TypeTableEntryIdBlock:
10300 case TypeTableEntryIdUnreachable:
10301 case TypeTableEntryIdVar:
10302 case TypeTableEntryIdArgTuple:
10303 case TypeTableEntryIdOpaque:
10304 ir_add_error_node(ira, un_op_instruction->base.source_node,
10305 buf_sprintf("unable to wrap type '%s' in error type", buf_ptr(&meta_type->name)));
10306 return ira->codegen->builtin_types.entry_invalid;
10307 }
10308 zig_unreachable();
10309}
10310
10311
10312static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {11361static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
10313 IrInstruction *value = un_op_instruction->value->other;11362 IrInstruction *value = un_op_instruction->value->other;
1031411363
...@@ -10364,7 +11413,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op...@@ -10364,7 +11413,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
10364 case TypeTableEntryIdNullLit:11413 case TypeTableEntryIdNullLit:
10365 case TypeTableEntryIdMaybe:11414 case TypeTableEntryIdMaybe:
10366 case TypeTableEntryIdErrorUnion:11415 case TypeTableEntryIdErrorUnion:
10367 case TypeTableEntryIdPureError:11416 case TypeTableEntryIdErrorSet:
10368 case TypeTableEntryIdEnum:11417 case TypeTableEntryIdEnum:
10369 case TypeTableEntryIdUnion:11418 case TypeTableEntryIdUnion:
10370 case TypeTableEntryIdFn:11419 case TypeTableEntryIdFn:
...@@ -10474,8 +11523,6 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio...@@ -10474,8 +11523,6 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio
10474 return ir_analyze_dereference(ira, un_op_instruction);11523 return ir_analyze_dereference(ira, un_op_instruction);
10475 case IrUnOpMaybe:11524 case IrUnOpMaybe:
10476 return ir_analyze_maybe(ira, un_op_instruction);11525 return ir_analyze_maybe(ira, un_op_instruction);
10477 case IrUnOpError:
10478 return ir_analyze_unary_prefix_op_err(ira, un_op_instruction);
10479 }11526 }
10480 zig_unreachable();11527 zig_unreachable();
10481}11528}
...@@ -10633,6 +11680,9 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP...@@ -10633,6 +11680,9 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
10633 IrInstruction *branch_instruction = predecessor->instruction_list.pop();11680 IrInstruction *branch_instruction = predecessor->instruction_list.pop();
10634 ir_set_cursor_at_end(&ira->new_irb, predecessor);11681 ir_set_cursor_at_end(&ira->new_irb, predecessor);
10635 IrInstruction *casted_value = ir_implicit_cast(ira, new_value, resolved_type);11682 IrInstruction *casted_value = ir_implicit_cast(ira, new_value, resolved_type);
11683 if (casted_value == ira->codegen->invalid_instruction) {
11684 return ira->codegen->builtin_types.entry_invalid;
11685 }
10636 new_incoming_values.items[i] = casted_value;11686 new_incoming_values.items[i] = casted_value;
10637 predecessor->instruction_list.append(branch_instruction);11687 predecessor->instruction_list.append(branch_instruction);
1063811688
...@@ -11048,6 +12098,25 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field...@@ -11048,6 +12098,25 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
11048 }12098 }
11049}12099}
1105012100
12101static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, AstNode *source_node) {
12102 LinkLib *link_lib = add_link_lib(ira->codegen, lib_name);
12103 for (size_t i = 0; i < link_lib->symbols.length; i += 1) {
12104 Buf *existing_symbol_name = link_lib->symbols.at(i);
12105 if (buf_eql_buf(existing_symbol_name, symbol_name)) {
12106 return;
12107 }
12108 }
12109 for (size_t i = 0; i < ira->codegen->forbidden_libs.length; i += 1) {
12110 Buf *forbidden_lib_name = ira->codegen->forbidden_libs.at(i);
12111 if (buf_eql_buf(lib_name, forbidden_lib_name)) {
12112 ir_add_error_node(ira, source_node,
12113 buf_sprintf("linking against forbidden library '%s'", buf_ptr(symbol_name)));
12114 }
12115 }
12116 link_lib->symbols.append(symbol_name);
12117}
12118
12119
11051static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) {12120static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) {
11052 bool pointer_only = false;12121 bool pointer_only = false;
11053 resolve_top_level_decl(ira->codegen, tld, pointer_only, source_instruction->source_node);12122 resolve_top_level_decl(ira->codegen, tld, pointer_only, source_instruction->source_node);
...@@ -11063,7 +12132,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source...@@ -11063,7 +12132,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
11063 TldVar *tld_var = (TldVar *)tld;12132 TldVar *tld_var = (TldVar *)tld;
11064 VariableTableEntry *var = tld_var->var;12133 VariableTableEntry *var = tld_var->var;
11065 if (tld_var->extern_lib_name != nullptr) {12134 if (tld_var->extern_lib_name != nullptr) {
11066 add_link_lib_symbol(ira->codegen, tld_var->extern_lib_name, &var->name);12135 add_link_lib_symbol(ira, tld_var->extern_lib_name, &var->name, source_instruction->source_node);
11067 }12136 }
1106812137
11069 return ir_analyze_var_ptr(ira, source_instruction, var, false, false);12138 return ir_analyze_var_ptr(ira, source_instruction, var, false, false);
...@@ -11085,7 +12154,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source...@@ -11085,7 +12154,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
11085 const_val->data.x_fn.fn_entry = fn_entry;12154 const_val->data.x_fn.fn_entry = fn_entry;
1108612155
11087 if (tld_fn->extern_lib_name != nullptr) {12156 if (tld_fn->extern_lib_name != nullptr) {
11088 add_link_lib_symbol(ira->codegen, tld_fn->extern_lib_name, &fn_entry->symbol_name);12157 add_link_lib_symbol(ira, tld_fn->extern_lib_name, &fn_entry->symbol_name, source_instruction->source_node);
11089 }12158 }
1109012159
11091 bool ptr_is_const = true;12160 bool ptr_is_const = true;
...@@ -11097,6 +12166,17 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source...@@ -11097,6 +12166,17 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
11097 zig_unreachable();12166 zig_unreachable();
11098}12167}
1109912168
12169static ErrorTableEntry *find_err_table_entry(TypeTableEntry *err_set_type, Buf *field_name) {
12170 assert(err_set_type->id == TypeTableEntryIdErrorSet);
12171 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
12172 ErrorTableEntry *err_table_entry = err_set_type->data.error_set.errors[i];
12173 if (buf_eql_buf(&err_table_entry->name, field_name)) {
12174 return err_table_entry;
12175 }
12176 }
12177 return nullptr;
12178}
12179
11100static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstructionFieldPtr *field_ptr_instruction) {12180static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstructionFieldPtr *field_ptr_instruction) {
11101 IrInstruction *container_ptr = field_ptr_instruction->container_ptr->other;12181 IrInstruction *container_ptr = field_ptr_instruction->container_ptr->other;
11102 if (type_is_invalid(container_ptr->value.type))12182 if (type_is_invalid(container_ptr->value.type))
...@@ -11238,23 +12318,52 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru...@@ -11238,23 +12318,52 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
11238 buf_sprintf("container '%s' has no member called '%s'",12318 buf_sprintf("container '%s' has no member called '%s'",
11239 buf_ptr(&child_type->name), buf_ptr(field_name)));12319 buf_ptr(&child_type->name), buf_ptr(field_name)));
11240 return ira->codegen->builtin_types.entry_invalid;12320 return ira->codegen->builtin_types.entry_invalid;
11241 } else if (child_type->id == TypeTableEntryIdPureError) {12321 } else if (child_type->id == TypeTableEntryIdErrorSet) {
11242 auto err_table_entry = ira->codegen->error_table.maybe_get(field_name);12322 ErrorTableEntry *err_entry;
11243 if (err_table_entry) {12323 TypeTableEntry *err_set_type;
11244 ConstExprValue *const_val = create_const_vals(1);12324 if (type_is_global_error_set(child_type)) {
11245 const_val->special = ConstValSpecialStatic;12325 auto existing_entry = ira->codegen->error_table.maybe_get(field_name);
11246 const_val->type = child_type;12326 if (existing_entry) {
11247 const_val->data.x_pure_err = err_table_entry->value;12327 err_entry = existing_entry->value;
1124812328 } else {
11249 bool ptr_is_const = true;12329 err_entry = allocate<ErrorTableEntry>(1);
11250 bool ptr_is_volatile = false;12330 err_entry->decl_node = field_ptr_instruction->base.source_node;
11251 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val,12331 buf_init_from_buf(&err_entry->name, field_name);
11252 child_type, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);12332 size_t error_value_count = ira->codegen->errors_by_index.length;
12333 assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ira->codegen->err_tag_type->data.integral.bit_count));
12334 err_entry->value = error_value_count;
12335 ira->codegen->errors_by_index.append(err_entry);
12336 ira->codegen->err_enumerators.append(ZigLLVMCreateDebugEnumerator(ira->codegen->dbuilder,
12337 buf_ptr(field_name), error_value_count));
12338 ira->codegen->error_table.put(field_name, err_entry);
12339 }
12340 if (err_entry->set_with_only_this_in_it == nullptr) {
12341 err_entry->set_with_only_this_in_it = make_err_set_with_one_item(ira->codegen,
12342 field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node,
12343 err_entry);
12344 }
12345 err_set_type = err_entry->set_with_only_this_in_it;
12346 } else {
12347 if (!resolve_inferred_error_set(ira, child_type, field_ptr_instruction->base.source_node)) {
12348 return ira->codegen->builtin_types.entry_invalid;
12349 }
12350 err_entry = find_err_table_entry(child_type, field_name);
12351 if (err_entry == nullptr) {
12352 ir_add_error(ira, &field_ptr_instruction->base,
12353 buf_sprintf("no error named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&child_type->name)));
12354 return ira->codegen->builtin_types.entry_invalid;
12355 }
12356 err_set_type = child_type;
11253 }12357 }
12358 ConstExprValue *const_val = create_const_vals(1);
12359 const_val->special = ConstValSpecialStatic;
12360 const_val->type = err_set_type;
12361 const_val->data.x_err_set = err_entry;
1125412362
11255 ir_add_error(ira, &field_ptr_instruction->base,12363 bool ptr_is_const = true;
11256 buf_sprintf("use of undeclared error value '%s'", buf_ptr(field_name)));12364 bool ptr_is_volatile = false;
11257 return ira->codegen->builtin_types.entry_invalid;12365 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val,
12366 err_set_type, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
11258 } else if (child_type->id == TypeTableEntryIdInt) {12367 } else if (child_type->id == TypeTableEntryIdInt) {
11259 if (buf_eql_str(field_name, "bit_count")) {12368 if (buf_eql_str(field_name, "bit_count")) {
11260 bool ptr_is_const = true;12369 bool ptr_is_const = true;
...@@ -11337,11 +12446,18 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru...@@ -11337,11 +12446,18 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
11337 return ira->codegen->builtin_types.entry_invalid;12446 return ira->codegen->builtin_types.entry_invalid;
11338 }12447 }
11339 } else if (child_type->id == TypeTableEntryIdErrorUnion) {12448 } else if (child_type->id == TypeTableEntryIdErrorUnion) {
11340 if (buf_eql_str(field_name, "Child")) {12449 if (buf_eql_str(field_name, "Payload")) {
12450 bool ptr_is_const = true;
12451 bool ptr_is_volatile = false;
12452 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
12453 create_const_type(ira->codegen, child_type->data.error_union.payload_type),
12454 ira->codegen->builtin_types.entry_type,
12455 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
12456 } else if (buf_eql_str(field_name, "ErrorSet")) {
11341 bool ptr_is_const = true;12457 bool ptr_is_const = true;
11342 bool ptr_is_volatile = false;12458 bool ptr_is_volatile = false;
11343 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,12459 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
11344 create_const_type(ira->codegen, child_type->data.error.child_type),12460 create_const_type(ira->codegen, child_type->data.error_union.err_set_type),
11345 ira->codegen->builtin_types.entry_type,12461 ira->codegen->builtin_types.entry_type,
11346 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);12462 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
11347 } else {12463 } else {
...@@ -11528,7 +12644,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi...@@ -11528,7 +12644,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
11528 case TypeTableEntryIdStruct:12644 case TypeTableEntryIdStruct:
11529 case TypeTableEntryIdMaybe:12645 case TypeTableEntryIdMaybe:
11530 case TypeTableEntryIdErrorUnion:12646 case TypeTableEntryIdErrorUnion:
11531 case TypeTableEntryIdPureError:12647 case TypeTableEntryIdErrorSet:
11532 case TypeTableEntryIdEnum:12648 case TypeTableEntryIdEnum:
11533 case TypeTableEntryIdUnion:12649 case TypeTableEntryIdUnion:
11534 case TypeTableEntryIdFn:12650 case TypeTableEntryIdFn:
...@@ -11795,7 +12911,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,...@@ -11795,7 +12911,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
11795 case TypeTableEntryIdNumLitInt:12911 case TypeTableEntryIdNumLitInt:
11796 case TypeTableEntryIdMaybe:12912 case TypeTableEntryIdMaybe:
11797 case TypeTableEntryIdErrorUnion:12913 case TypeTableEntryIdErrorUnion:
11798 case TypeTableEntryIdPureError:12914 case TypeTableEntryIdErrorSet:
11799 case TypeTableEntryIdEnum:12915 case TypeTableEntryIdEnum:
11800 case TypeTableEntryIdUnion:12916 case TypeTableEntryIdUnion:
11801 case TypeTableEntryIdFn:12917 case TypeTableEntryIdFn:
...@@ -11903,7 +13019,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,...@@ -11903,7 +13019,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
11903 case TypeTableEntryIdNumLitInt:13019 case TypeTableEntryIdNumLitInt:
11904 case TypeTableEntryIdMaybe:13020 case TypeTableEntryIdMaybe:
11905 case TypeTableEntryIdErrorUnion:13021 case TypeTableEntryIdErrorUnion:
11906 case TypeTableEntryIdPureError:13022 case TypeTableEntryIdErrorSet:
11907 case TypeTableEntryIdEnum:13023 case TypeTableEntryIdEnum:
11908 case TypeTableEntryIdUnion:13024 case TypeTableEntryIdUnion:
11909 case TypeTableEntryIdFn:13025 case TypeTableEntryIdFn:
...@@ -11956,7 +13072,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,...@@ -11956,7 +13072,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
11956 case TypeTableEntryIdStruct:13072 case TypeTableEntryIdStruct:
11957 case TypeTableEntryIdMaybe:13073 case TypeTableEntryIdMaybe:
11958 case TypeTableEntryIdErrorUnion:13074 case TypeTableEntryIdErrorUnion:
11959 case TypeTableEntryIdPureError:13075 case TypeTableEntryIdErrorSet:
11960 case TypeTableEntryIdEnum:13076 case TypeTableEntryIdEnum:
11961 case TypeTableEntryIdUnion:13077 case TypeTableEntryIdUnion:
11962 case TypeTableEntryIdFn:13078 case TypeTableEntryIdFn:
...@@ -12291,7 +13407,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,...@@ -12291,7 +13407,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
12291 case TypeTableEntryIdPointer:13407 case TypeTableEntryIdPointer:
12292 case TypeTableEntryIdFn:13408 case TypeTableEntryIdFn:
12293 case TypeTableEntryIdNamespace:13409 case TypeTableEntryIdNamespace:
12294 case TypeTableEntryIdPureError:13410 case TypeTableEntryIdErrorSet:
12295 if (pointee_val) {13411 if (pointee_val) {
12296 ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);13412 ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);
12297 copy_const_val(out_val, pointee_val, true);13413 copy_const_val(out_val, pointee_val, true);
...@@ -12361,8 +13477,6 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,...@@ -12361,8 +13477,6 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
12361 return target_type;13477 return target_type;
12362 }13478 }
12363 case TypeTableEntryIdErrorUnion:13479 case TypeTableEntryIdErrorUnion:
12364 // see https://github.com/andrewrk/zig/issues/632
12365 zig_panic("TODO switch on error union");
12366 case TypeTableEntryIdUnreachable:13480 case TypeTableEntryIdUnreachable:
12367 case TypeTableEntryIdArray:13481 case TypeTableEntryIdArray:
12368 case TypeTableEntryIdStruct:13482 case TypeTableEntryIdStruct:
...@@ -12887,7 +14001,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_...@@ -12887,7 +14001,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
12887 case TypeTableEntryIdNullLit:14001 case TypeTableEntryIdNullLit:
12888 case TypeTableEntryIdMaybe:14002 case TypeTableEntryIdMaybe:
12889 case TypeTableEntryIdErrorUnion:14003 case TypeTableEntryIdErrorUnion:
12890 case TypeTableEntryIdPureError:14004 case TypeTableEntryIdErrorSet:
12891 case TypeTableEntryIdUnion:14005 case TypeTableEntryIdUnion:
12892 case TypeTableEntryIdFn:14006 case TypeTableEntryIdFn:
12893 case TypeTableEntryIdNamespace:14007 case TypeTableEntryIdNamespace:
...@@ -12975,7 +14089,7 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc...@@ -12975,7 +14089,7 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc
12975 TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);14089 TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
12976 TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type);14090 TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type);
12977 if (casted_value->value.special == ConstValSpecialStatic) {14091 if (casted_value->value.special == ConstValSpecialStatic) {
12978 ErrorTableEntry *err = casted_value->value.data.x_pure_err;14092 ErrorTableEntry *err = casted_value->value.data.x_err_set;
12979 if (!err->cached_error_name_val) {14093 if (!err->cached_error_name_val) {
12980 ConstExprValue *array_val = create_const_str_lit(ira->codegen, &err->name);14094 ConstExprValue *array_val = create_const_str_lit(ira->codegen, &err->name);
12981 err->cached_error_name_val = create_const_slice(ira->codegen, array_val, 0, buf_len(&err->name), true);14095 err->cached_error_name_val = create_const_slice(ira->codegen, array_val, 0, buf_len(&err->name), true);
...@@ -13956,6 +15070,15 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns...@@ -13956,6 +15070,15 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns
13956 result = container_type->data.structure.src_field_count;15070 result = container_type->data.structure.src_field_count;
13957 } else if (container_type->id == TypeTableEntryIdUnion) {15071 } else if (container_type->id == TypeTableEntryIdUnion) {
13958 result = container_type->data.unionation.src_field_count;15072 result = container_type->data.unionation.src_field_count;
15073 } else if (container_type->id == TypeTableEntryIdErrorSet) {
15074 if (!resolve_inferred_error_set(ira, container_type, instruction->base.source_node)) {
15075 return ira->codegen->builtin_types.entry_invalid;
15076 }
15077 if (type_is_global_error_set(container_type)) {
15078 ir_add_error(ira, &instruction->base, buf_sprintf("global error set member count not available at comptime"));
15079 return ira->codegen->builtin_types.entry_invalid;
15080 }
15081 result = container_type->data.error_set.err_count;
13959 } else {15082 } else {
13960 ir_add_error(ira, &instruction->base, buf_sprintf("no value count available for type '%s'", buf_ptr(&container_type->name)));15083 ir_add_error(ira, &instruction->base, buf_sprintf("no value count available for type '%s'", buf_ptr(&container_type->name)));
13961 return ira->codegen->builtin_types.entry_invalid;15084 return ira->codegen->builtin_types.entry_invalid;
...@@ -14120,7 +15243,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc...@@ -14120,7 +15243,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc
14120 case TypeTableEntryIdStruct:15243 case TypeTableEntryIdStruct:
14121 case TypeTableEntryIdMaybe:15244 case TypeTableEntryIdMaybe:
14122 case TypeTableEntryIdErrorUnion:15245 case TypeTableEntryIdErrorUnion:
14123 case TypeTableEntryIdPureError:15246 case TypeTableEntryIdErrorSet:
14124 case TypeTableEntryIdEnum:15247 case TypeTableEntryIdEnum:
14125 case TypeTableEntryIdUnion:15248 case TypeTableEntryIdUnion:
14126 case TypeTableEntryIdFn:15249 case TypeTableEntryIdFn:
...@@ -14251,9 +15374,22 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc...@@ -14251,9 +15374,22 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc
14251 }15374 }
14252 }15375 }
1425315376
15377 TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type;
15378 if (!resolve_inferred_error_set(ira, err_set_type, instruction->base.source_node)) {
15379 return ira->codegen->builtin_types.entry_invalid;
15380 }
15381 if (!type_is_global_error_set(err_set_type) &&
15382 err_set_type->data.error_set.err_count == 0)
15383 {
15384 assert(err_set_type->data.error_set.infer_fn == nullptr);
15385 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
15386 out_val->data.x_bool = false;
15387 return ira->codegen->builtin_types.entry_bool;
15388 }
15389
14254 ir_build_test_err_from(&ira->new_irb, &instruction->base, value);15390 ir_build_test_err_from(&ira->new_irb, &instruction->base, value);
14255 return ira->codegen->builtin_types.entry_bool;15391 return ira->codegen->builtin_types.entry_bool;
14256 } else if (type_entry->id == TypeTableEntryIdPureError) {15392 } else if (type_entry->id == TypeTableEntryIdErrorSet) {
14257 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);15393 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
14258 out_val->data.x_bool = true;15394 out_val->data.x_bool = true;
14259 return ira->codegen->builtin_types.entry_bool;15395 return ira->codegen->builtin_types.entry_bool;
...@@ -14289,13 +15425,13 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira,...@@ -14289,13 +15425,13 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira,
14289 assert(err);15425 assert(err);
1429015426
14291 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);15427 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
14292 out_val->data.x_pure_err = err;15428 out_val->data.x_err_set = err;
14293 return ira->codegen->builtin_types.entry_pure_error;15429 return type_entry->data.error_union.err_set_type;
14294 }15430 }
14295 }15431 }
1429615432
14297 ir_build_unwrap_err_code_from(&ira->new_irb, &instruction->base, value);15433 ir_build_unwrap_err_code_from(&ira->new_irb, &instruction->base, value);
14298 return ira->codegen->builtin_types.entry_pure_error;15434 return type_entry->data.error_union.err_set_type;
14299 } else {15435 } else {
14300 ir_add_error(ira, value,15436 ir_add_error(ira, value,
14301 buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name)));15437 buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name)));
...@@ -14319,10 +15455,10 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,...@@ -14319,10 +15455,10 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
14319 if (type_is_invalid(type_entry)) {15455 if (type_is_invalid(type_entry)) {
14320 return ira->codegen->builtin_types.entry_invalid;15456 return ira->codegen->builtin_types.entry_invalid;
14321 } else if (type_entry->id == TypeTableEntryIdErrorUnion) {15457 } else if (type_entry->id == TypeTableEntryIdErrorUnion) {
14322 TypeTableEntry *child_type = type_entry->data.error.child_type;15458 TypeTableEntry *payload_type = type_entry->data.error_union.payload_type;
14323 TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, child_type,15459 TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, payload_type,
14324 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,15460 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
14325 get_abi_alignment(ira->codegen, child_type), 0, 0);15461 get_abi_alignment(ira->codegen, payload_type), 0, 0);
14326 if (instr_is_comptime(value)) {15462 if (instr_is_comptime(value)) {
14327 ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);15463 ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
14328 if (!ptr_val)15464 if (!ptr_val)
...@@ -14332,7 +15468,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,...@@ -14332,7 +15468,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
14332 ErrorTableEntry *err = err_union_val->data.x_err_union.err;15468 ErrorTableEntry *err = err_union_val->data.x_err_union.err;
14333 if (err != nullptr) {15469 if (err != nullptr) {
14334 ir_add_error(ira, &instruction->base,15470 ir_add_error(ira, &instruction->base,
14335 buf_sprintf("unable to unwrap error '%s'", buf_ptr(&err->name)));15471 buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
14336 return ira->codegen->builtin_types.entry_invalid;15472 return ira->codegen->builtin_types.entry_invalid;
14337 }15473 }
1433815474
...@@ -14357,6 +15493,12 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc...@@ -14357,6 +15493,12 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
14357 AstNode *proto_node = instruction->base.source_node;15493 AstNode *proto_node = instruction->base.source_node;
14358 assert(proto_node->type == NodeTypeFnProto);15494 assert(proto_node->type == NodeTypeFnProto);
1435915495
15496 if (proto_node->data.fn_proto.auto_err_set) {
15497 ir_add_error(ira, &instruction->base,
15498 buf_sprintf("inferring error set of return type valid only for function definitions"));
15499 return ira->codegen->builtin_types.entry_invalid;
15500 }
15501
14360 FnTypeId fn_type_id = {0};15502 FnTypeId fn_type_id = {0};
14361 init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length);15503 init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length);
1436215504
...@@ -14482,6 +15624,57 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira...@@ -14482,6 +15624,57 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
14482 }15624 }
14483 }15625 }
14484 }15626 }
15627 } else if (switch_type->id == TypeTableEntryIdErrorSet) {
15628 if (!resolve_inferred_error_set(ira, switch_type, target_value->source_node)) {
15629 return ira->codegen->builtin_types.entry_invalid;
15630 }
15631
15632 AstNode **field_prev_uses = allocate<AstNode *>(ira->codegen->errors_by_index.length);
15633
15634 for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) {
15635 IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i];
15636
15637 IrInstruction *start_value = range->start->other;
15638 if (type_is_invalid(start_value->value.type))
15639 return ira->codegen->builtin_types.entry_invalid;
15640
15641 IrInstruction *end_value = range->end->other;
15642 if (type_is_invalid(end_value->value.type))
15643 return ira->codegen->builtin_types.entry_invalid;
15644
15645 assert(start_value->value.type->id == TypeTableEntryIdErrorSet);
15646 uint32_t start_index = start_value->value.data.x_err_set->value;
15647
15648 assert(end_value->value.type->id == TypeTableEntryIdErrorSet);
15649 uint32_t end_index = end_value->value.data.x_err_set->value;
15650
15651 if (start_index != end_index) {
15652 ir_add_error(ira, end_value, buf_sprintf("ranges not allowed when switching on errors"));
15653 return ira->codegen->builtin_types.entry_invalid;
15654 }
15655
15656 AstNode *prev_node = field_prev_uses[start_index];
15657 if (prev_node != nullptr) {
15658 Buf *err_name = &ira->codegen->errors_by_index.at(start_index)->name;
15659 ErrorMsg *msg = ir_add_error(ira, start_value,
15660 buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&switch_type->name), buf_ptr(err_name)));
15661 add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value is here"));
15662 }
15663 field_prev_uses[start_index] = start_value->source_node;
15664 }
15665 if (!instruction->have_else_prong) {
15666 for (uint32_t i = 0; i < switch_type->data.error_set.err_count; i += 1) {
15667 ErrorTableEntry *err_entry = switch_type->data.error_set.errors[i];
15668
15669 AstNode *prev_node = field_prev_uses[err_entry->value];
15670 if (prev_node == nullptr) {
15671 ir_add_error(ira, &instruction->base,
15672 buf_sprintf("error.%s not handled in switch", buf_ptr(&err_entry->name)));
15673 }
15674 }
15675 }
15676
15677 free(field_prev_uses);
14485 } else if (switch_type->id == TypeTableEntryIdInt) {15678 } else if (switch_type->id == TypeTableEntryIdInt) {
14486 RangeSet rs = {0};15679 RangeSet rs = {0};
14487 for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) {15680 for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) {
...@@ -14774,7 +15967,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue...@@ -14774,7 +15967,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
14774 zig_panic("TODO buf_write_value_bytes maybe type");15967 zig_panic("TODO buf_write_value_bytes maybe type");
14775 case TypeTableEntryIdErrorUnion:15968 case TypeTableEntryIdErrorUnion:
14776 zig_panic("TODO buf_write_value_bytes error union");15969 zig_panic("TODO buf_write_value_bytes error union");
14777 case TypeTableEntryIdPureError:15970 case TypeTableEntryIdErrorSet:
14778 zig_panic("TODO buf_write_value_bytes pure error type");15971 zig_panic("TODO buf_write_value_bytes pure error type");
14779 case TypeTableEntryIdEnum:15972 case TypeTableEntryIdEnum:
14780 zig_panic("TODO buf_write_value_bytes enum type");15973 zig_panic("TODO buf_write_value_bytes enum type");
...@@ -14832,7 +16025,7 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue...@@ -14832,7 +16025,7 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
14832 zig_panic("TODO buf_read_value_bytes maybe type");16025 zig_panic("TODO buf_read_value_bytes maybe type");
14833 case TypeTableEntryIdErrorUnion:16026 case TypeTableEntryIdErrorUnion:
14834 zig_panic("TODO buf_read_value_bytes error union");16027 zig_panic("TODO buf_read_value_bytes error union");
14835 case TypeTableEntryIdPureError:16028 case TypeTableEntryIdErrorSet:
14836 zig_panic("TODO buf_read_value_bytes pure error type");16029 zig_panic("TODO buf_read_value_bytes pure error type");
14837 case TypeTableEntryIdEnum:16030 case TypeTableEntryIdEnum:
14838 zig_panic("TODO buf_read_value_bytes enum type");16031 zig_panic("TODO buf_read_value_bytes enum type");
...@@ -15010,7 +16203,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,...@@ -15010,7 +16203,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
15010 return ira->codegen->builtin_types.entry_invalid;16203 return ira->codegen->builtin_types.entry_invalid;
1501116204
15012 if (tld_var->extern_lib_name != nullptr) {16205 if (tld_var->extern_lib_name != nullptr) {
15013 add_link_lib_symbol(ira->codegen, tld_var->extern_lib_name, &var->name);16206 add_link_lib_symbol(ira, tld_var->extern_lib_name, &var->name, instruction->base.source_node);
15014 }16207 }
1501516208
15016 if (lval.is_ptr) {16209 if (lval.is_ptr) {
...@@ -15029,7 +16222,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,...@@ -15029,7 +16222,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
15029 assert(fn_entry->type_entry);16222 assert(fn_entry->type_entry);
1503016223
15031 if (tld_fn->extern_lib_name != nullptr) {16224 if (tld_fn->extern_lib_name != nullptr) {
15032 add_link_lib_symbol(ira->codegen, tld_fn->extern_lib_name, &fn_entry->symbol_name);16225 add_link_lib_symbol(ira, tld_fn->extern_lib_name, &fn_entry->symbol_name, instruction->base.source_node);
15033 }16226 }
1503416227
15035 IrInstruction *ref_instruction = ir_create_const_fn(&ira->new_irb, instruction->base.scope,16228 IrInstruction *ref_instruction = ir_create_const_fn(&ira->new_irb, instruction->base.scope,
...@@ -15443,6 +16636,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -15443,6 +16636,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
15443 return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction);16636 return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction);
15444 case IrInstructionIdErrorReturnTrace:16637 case IrInstructionIdErrorReturnTrace:
15445 return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction);16638 return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction);
16639 case IrInstructionIdErrorUnion:
16640 return ir_analyze_instruction_error_union(ira, (IrInstructionErrorUnion *)instruction);
15446 }16641 }
15447 zig_unreachable();16642 zig_unreachable();
15448}16643}
...@@ -15628,6 +16823,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -15628,6 +16823,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
15628 case IrInstructionIdArgType:16823 case IrInstructionIdArgType:
15629 case IrInstructionIdTagType:16824 case IrInstructionIdTagType:
15630 case IrInstructionIdErrorReturnTrace:16825 case IrInstructionIdErrorReturnTrace:
16826 case IrInstructionIdErrorUnion:
15631 return false;16827 return false;
15632 case IrInstructionIdAsm:16828 case IrInstructionIdAsm:
15633 {16829 {
src/ir_print.cpp+10-2
...@@ -130,6 +130,8 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) {...@@ -130,6 +130,8 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) {
130 return "++";130 return "++";
131 case IrBinOpArrayMult:131 case IrBinOpArrayMult:
132 return "**";132 return "**";
133 case IrBinOpMergeErrorSets:
134 return "||";
133 }135 }
134 zig_unreachable();136 zig_unreachable();
135}137}
...@@ -148,8 +150,6 @@ static const char *ir_un_op_id_str(IrUnOp op_id) {...@@ -148,8 +150,6 @@ static const char *ir_un_op_id_str(IrUnOp op_id) {
148 return "*";150 return "*";
149 case IrUnOpMaybe:151 case IrUnOpMaybe:
150 return "?";152 return "?";
151 case IrUnOpError:
152 return "%";
153 }153 }
154 zig_unreachable();154 zig_unreachable();
155}155}
...@@ -1004,6 +1004,11 @@ static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTr...@@ -1004,6 +1004,11 @@ static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTr
1004 fprintf(irp->f, "@errorReturnTrace()");1004 fprintf(irp->f, "@errorReturnTrace()");
1005}1005}
10061006
1007static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruction) {
1008 ir_print_other_instruction(irp, instruction->err_set);
1009 fprintf(irp->f, "!");
1010 ir_print_other_instruction(irp, instruction->payload);
1011}
10071012
1008static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1013static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1009 ir_print_prefix(irp, instruction);1014 ir_print_prefix(irp, instruction);
...@@ -1322,6 +1327,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1322,6 +1327,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1322 case IrInstructionIdErrorReturnTrace:1327 case IrInstructionIdErrorReturnTrace:
1323 ir_print_error_return_trace(irp, (IrInstructionErrorReturnTrace *)instruction);1328 ir_print_error_return_trace(irp, (IrInstructionErrorReturnTrace *)instruction);
1324 break;1329 break;
1330 case IrInstructionIdErrorUnion:
1331 ir_print_error_union(irp, (IrInstructionErrorUnion *)instruction);
1332 break;
1325 }1333 }
1326 fprintf(irp->f, "\n");1334 fprintf(irp->f, "\n");
1327}1335}
src/main.cpp+8
...@@ -66,6 +66,7 @@ static int usage(const char *arg0) {...@@ -66,6 +66,7 @@ static int usage(const char *arg0) {
66 " --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides\n"66 " --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides\n"
67 " --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides\n"67 " --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides\n"
68 " --library [lib] link against lib\n"68 " --library [lib] link against lib\n"
69 " --forbid-library [lib] make it an error to link against lib\n"
69 " --library-path [dir] add a directory to the library search path\n"70 " --library-path [dir] add a directory to the library search path\n"
70 " --linker-script [path] use a custom linker script\n"71 " --linker-script [path] use a custom linker script\n"
71 " --object [obj] add object file to build\n"72 " --object [obj] add object file to build\n"
...@@ -309,6 +310,7 @@ int main(int argc, char **argv) {...@@ -309,6 +310,7 @@ int main(int argc, char **argv) {
309 ZigList<const char *> llvm_argv = {0};310 ZigList<const char *> llvm_argv = {0};
310 ZigList<const char *> lib_dirs = {0};311 ZigList<const char *> lib_dirs = {0};
311 ZigList<const char *> link_libs = {0};312 ZigList<const char *> link_libs = {0};
313 ZigList<const char *> forbidden_link_libs = {0};
312 ZigList<const char *> frameworks = {0};314 ZigList<const char *> frameworks = {0};
313 int err;315 int err;
314 const char *target_arch = nullptr;316 const char *target_arch = nullptr;
...@@ -605,6 +607,8 @@ int main(int argc, char **argv) {...@@ -605,6 +607,8 @@ int main(int argc, char **argv) {
605 lib_dirs.append(argv[i]);607 lib_dirs.append(argv[i]);
606 } else if (strcmp(arg, "--library") == 0) {608 } else if (strcmp(arg, "--library") == 0) {
607 link_libs.append(argv[i]);609 link_libs.append(argv[i]);
610 } else if (strcmp(arg, "--forbid-library") == 0) {
611 forbidden_link_libs.append(argv[i]);
608 } else if (strcmp(arg, "--object") == 0) {612 } else if (strcmp(arg, "--object") == 0) {
609 objects.append(argv[i]);613 objects.append(argv[i]);
610 } else if (strcmp(arg, "--assembly") == 0) {614 } else if (strcmp(arg, "--assembly") == 0) {
...@@ -817,6 +821,10 @@ int main(int argc, char **argv) {...@@ -817,6 +821,10 @@ int main(int argc, char **argv) {
817 LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i)));821 LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i)));
818 link_lib->provided_explicitly = true;822 link_lib->provided_explicitly = true;
819 }823 }
824 for (size_t i = 0; i < forbidden_link_libs.length; i += 1) {
825 Buf *forbidden_link_lib = buf_create_from_str(forbidden_link_libs.at(i));
826 codegen_add_forbidden_lib(g, forbidden_link_lib);
827 }
820 for (size_t i = 0; i < frameworks.length; i += 1) {828 for (size_t i = 0; i < frameworks.length; i += 1) {
821 codegen_add_framework(g, frameworks.at(i));829 codegen_add_framework(g, frameworks.at(i));
822 }830 }
src/parser.cpp+74-42
...@@ -221,6 +221,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, size_t *token_index, bo...@@ -221,6 +221,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, size_t *token_index, bo
221static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory);221static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory);
222static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory);222static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory);
223static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index);223static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index);
224static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index);
224225
225static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {226static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
226 if (token->id == token_id) {227 if (token->id == token_id) {
...@@ -240,7 +241,28 @@ static Token *ast_eat_token(ParseContext *pc, size_t *token_index, TokenId token...@@ -240,7 +241,28 @@ static Token *ast_eat_token(ParseContext *pc, size_t *token_index, TokenId token
240}241}
241242
242/*243/*
243TypeExpr = PrefixOpExpression | "var"244ErrorSetExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression
245*/
246static AstNode *ast_parse_error_set_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
247 AstNode *prefix_op_expr = ast_parse_prefix_op_expr(pc, token_index, mandatory);
248 if (!prefix_op_expr) {
249 return nullptr;
250 }
251 Token *token = &pc->tokens->at(*token_index);
252 if (token->id == TokenIdBang) {
253 *token_index += 1;
254 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
255 node->data.bin_op_expr.op1 = prefix_op_expr;
256 node->data.bin_op_expr.bin_op = BinOpTypeErrorUnion;
257 node->data.bin_op_expr.op2 = ast_parse_prefix_op_expr(pc, token_index, true);
258 return node;
259 } else {
260 return prefix_op_expr;
261 }
262}
263
264/*
265TypeExpr = ErrorSetExpr | "var"
244*/266*/
245static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool mandatory) {267static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
246 Token *token = &pc->tokens->at(*token_index);268 Token *token = &pc->tokens->at(*token_index);
...@@ -249,7 +271,7 @@ static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool...@@ -249,7 +271,7 @@ static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool
249 *token_index += 1;271 *token_index += 1;
250 return node;272 return node;
251 } else {273 } else {
252 return ast_parse_prefix_op_expr(pc, token_index, mandatory);274 return ast_parse_error_set_expr(pc, token_index, mandatory);
253 }275 }
254}276}
255277
...@@ -651,8 +673,9 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b...@@ -651,8 +673,9 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b
651}673}
652674
653/*675/*
654PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl | ("continue" option(":" Symbol))676PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl
655KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable"677KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable"
678ErrorSetDecl = "error" "{" list(Symbol, ",") "}"
656*/679*/
657static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {680static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
658 Token *token = &pc->tokens->at(*token_index);681 Token *token = &pc->tokens->at(*token_index);
...@@ -716,9 +739,31 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo...@@ -716,9 +739,31 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
716 *token_index += 1;739 *token_index += 1;
717 return node;740 return node;
718 } else if (token->id == TokenIdKeywordError) {741 } else if (token->id == TokenIdKeywordError) {
719 AstNode *node = ast_create_node(pc, NodeTypeErrorType, token);742 Token *next_token = &pc->tokens->at(*token_index + 1);
720 *token_index += 1;743 if (next_token->id == TokenIdLBrace) {
721 return node;744 AstNode *node = ast_create_node(pc, NodeTypeErrorSetDecl, token);
745 *token_index += 2;
746 for (;;) {
747 Token *item_tok = &pc->tokens->at(*token_index);
748 if (item_tok->id == TokenIdRBrace) {
749 *token_index += 1;
750 return node;
751 } else if (item_tok->id == TokenIdSymbol) {
752 AstNode *symbol_node = ast_parse_symbol(pc, token_index);
753 node->data.err_set_decl.decls.append(symbol_node);
754 Token *opt_comma_tok = &pc->tokens->at(*token_index);
755 if (opt_comma_tok->id == TokenIdComma) {
756 *token_index += 1;
757 }
758 } else {
759 ast_invalid_token_error(pc, item_tok);
760 }
761 }
762 } else {
763 AstNode *node = ast_create_node(pc, NodeTypeErrorType, token);
764 *token_index += 1;
765 return node;
766 }
722 } else if (token->id == TokenIdAtSign) {767 } else if (token->id == TokenIdAtSign) {
723 *token_index += 1;768 *token_index += 1;
724 Token *name_tok = &pc->tokens->at(*token_index);769 Token *name_tok = &pc->tokens->at(*token_index);
...@@ -950,7 +995,6 @@ static PrefixOp tok_to_prefix_op(Token *token) {...@@ -950,7 +995,6 @@ static PrefixOp tok_to_prefix_op(Token *token) {
950 case TokenIdTilde: return PrefixOpBinNot;995 case TokenIdTilde: return PrefixOpBinNot;
951 case TokenIdStar: return PrefixOpDereference;996 case TokenIdStar: return PrefixOpDereference;
952 case TokenIdMaybe: return PrefixOpMaybe;997 case TokenIdMaybe: return PrefixOpMaybe;
953 case TokenIdPercent: return PrefixOpError;
954 case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe;998 case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe;
955 case TokenIdStarStar: return PrefixOpDereference;999 case TokenIdStarStar: return PrefixOpDereference;
956 default: return PrefixOpInvalid;1000 default: return PrefixOpInvalid;
...@@ -997,8 +1041,8 @@ static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) {...@@ -997,8 +1041,8 @@ static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) {
997}1041}
9981042
999/*1043/*
1000PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression1044PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression
1001PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%" | "try"1045PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try"
1002*/1046*/
1003static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {1047static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
1004 Token *token = &pc->tokens->at(*token_index);1048 Token *token = &pc->tokens->at(*token_index);
...@@ -1028,7 +1072,7 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index,...@@ -1028,7 +1072,7 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index,
1028 node->column += 1;1072 node->column += 1;
1029 }1073 }
10301074
1031 AstNode *prefix_op_expr = ast_parse_prefix_op_expr(pc, token_index, true);1075 AstNode *prefix_op_expr = ast_parse_error_set_expr(pc, token_index, true);
1032 node->data.prefix_op_expr.primary_expr = prefix_op_expr;1076 node->data.prefix_op_expr.primary_expr = prefix_op_expr;
1033 node->data.prefix_op_expr.prefix_op = prefix_op;1077 node->data.prefix_op_expr.prefix_op = prefix_op;
10341078
...@@ -1043,12 +1087,14 @@ static BinOpType tok_to_mult_op(Token *token) {...@@ -1043,12 +1087,14 @@ static BinOpType tok_to_mult_op(Token *token) {
1043 case TokenIdStarStar: return BinOpTypeArrayMult;1087 case TokenIdStarStar: return BinOpTypeArrayMult;
1044 case TokenIdSlash: return BinOpTypeDiv;1088 case TokenIdSlash: return BinOpTypeDiv;
1045 case TokenIdPercent: return BinOpTypeMod;1089 case TokenIdPercent: return BinOpTypeMod;
1090 case TokenIdBang: return BinOpTypeErrorUnion;
1091 case TokenIdBarBar: return BinOpTypeMergeErrorSets;
1046 default: return BinOpTypeInvalid;1092 default: return BinOpTypeInvalid;
1047 }1093 }
1048}1094}
10491095
1050/*1096/*
1051MultiplyOperator = "*" | "/" | "%" | "**" | "*%"1097MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
1052*/1098*/
1053static BinOpType ast_parse_mult_op(ParseContext *pc, size_t *token_index, bool mandatory) {1099static BinOpType ast_parse_mult_op(ParseContext *pc, size_t *token_index, bool mandatory) {
1054 Token *token = &pc->tokens->at(*token_index);1100 Token *token = &pc->tokens->at(*token_index);
...@@ -2240,7 +2286,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand...@@ -2240,7 +2286,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
2240}2286}
22412287
2242/*2288/*
2243FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") TypeExpr2289FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
2244*/2290*/
2245static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {2291static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
2246 Token *first_token = &pc->tokens->at(*token_index);2292 Token *first_token = &pc->tokens->at(*token_index);
...@@ -2315,6 +2361,18 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m...@@ -2315,6 +2361,18 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
2315 ast_eat_token(pc, token_index, TokenIdRParen);2361 ast_eat_token(pc, token_index, TokenIdRParen);
2316 next_token = &pc->tokens->at(*token_index);2362 next_token = &pc->tokens->at(*token_index);
2317 }2363 }
2364 if (next_token->id == TokenIdKeywordError) {
2365 Token *maybe_lbrace_tok = &pc->tokens->at(*token_index + 1);
2366 if (maybe_lbrace_tok->id == TokenIdLBrace) {
2367 *token_index += 1;
2368 node->data.fn_proto.return_type = ast_create_node(pc, NodeTypeErrorType, next_token);
2369 return node;
2370 }
2371 } else if (next_token->id == TokenIdBang) {
2372 *token_index += 1;
2373 node->data.fn_proto.auto_err_set = true;
2374 next_token = &pc->tokens->at(*token_index);
2375 }
2318 node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, true);2376 node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, true);
23192377
2320 return node;2378 return node;
...@@ -2531,7 +2589,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,...@@ -2531,7 +2589,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
2531 Token *colon_token = &pc->tokens->at(*token_index);2589 Token *colon_token = &pc->tokens->at(*token_index);
2532 if (colon_token->id == TokenIdColon) {2590 if (colon_token->id == TokenIdColon) {
2533 *token_index += 1;2591 *token_index += 1;
2534 field_node->data.struct_field.type = ast_parse_prefix_op_expr(pc, token_index, true);2592 field_node->data.struct_field.type = ast_parse_type_expr(pc, token_index, true);
2535 }2593 }
2536 Token *eq_token = &pc->tokens->at(*token_index);2594 Token *eq_token = &pc->tokens->at(*token_index);
2537 if (eq_token->id == TokenIdEq) {2595 if (eq_token->id == TokenIdEq) {
...@@ -2559,26 +2617,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,...@@ -2559,26 +2617,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
2559 return node;2617 return node;
2560}2618}
25612619
2562/*
2563ErrorValueDecl : "error" "Symbol" ";"
2564*/
2565static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index) {
2566 Token *first_token = &pc->tokens->at(*token_index);
2567
2568 if (first_token->id != TokenIdKeywordError) {
2569 return nullptr;
2570 }
2571 *token_index += 1;
2572
2573 Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
2574 ast_eat_token(pc, token_index, TokenIdSemicolon);
2575
2576 AstNode *node = ast_create_node(pc, NodeTypeErrorValueDecl, first_token);
2577 node->data.error_value_decl.name = token_buf(name_tok);
2578
2579 return node;
2580}
2581
2582/*2620/*
2583TestDecl = "test" String Block2621TestDecl = "test" String Block
2584*/2622*/
...@@ -2611,12 +2649,6 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig...@@ -2611,12 +2649,6 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig
2611 continue;2649 continue;
2612 }2650 }
26132651
2614 AstNode *error_value_node = ast_parse_error_value_decl(pc, token_index);
2615 if (error_value_node) {
2616 top_level_decls->append(error_value_node);
2617 continue;
2618 }
2619
2620 AstNode *test_decl_node = ast_parse_test_decl_node(pc, token_index);2652 AstNode *test_decl_node = ast_parse_test_decl_node(pc, token_index);
2621 if (test_decl_node) {2653 if (test_decl_node) {
2622 top_level_decls->append(test_decl_node);2654 top_level_decls->append(test_decl_node);
...@@ -2744,9 +2776,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont...@@ -2744,9 +2776,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
2744 visit_field(&node->data.variable_declaration.align_expr, visit, context);2776 visit_field(&node->data.variable_declaration.align_expr, visit, context);
2745 visit_field(&node->data.variable_declaration.section_expr, visit, context);2777 visit_field(&node->data.variable_declaration.section_expr, visit, context);
2746 break;2778 break;
2747 case NodeTypeErrorValueDecl:
2748 // none
2749 break;
2750 case NodeTypeTestDecl:2779 case NodeTypeTestDecl:
2751 visit_field(&node->data.test_decl.body, visit, context);2780 visit_field(&node->data.test_decl.body, visit, context);
2752 break;2781 break;
...@@ -2899,5 +2928,8 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont...@@ -2899,5 +2928,8 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
2899 visit_field(&node->data.addr_of_expr.align_expr, visit, context);2928 visit_field(&node->data.addr_of_expr.align_expr, visit, context);
2900 visit_field(&node->data.addr_of_expr.op_expr, visit, context);2929 visit_field(&node->data.addr_of_expr.op_expr, visit, context);
2901 break;2930 break;
2931 case NodeTypeErrorSetDecl:
2932 visit_node_list(&node->data.err_set_decl.decls, visit, context);
2933 break;
2902 }2934 }
2903}2935}
src/tokenizer.cpp+25-4
...@@ -195,7 +195,8 @@ enum TokenizeState {...@@ -195,7 +195,8 @@ enum TokenizeState {
195 TokenizeStateSawMinusPercent,195 TokenizeStateSawMinusPercent,
196 TokenizeStateSawAmpersand,196 TokenizeStateSawAmpersand,
197 TokenizeStateSawCaret,197 TokenizeStateSawCaret,
198 TokenizeStateSawPipe,198 TokenizeStateSawBar,
199 TokenizeStateSawBarBar,
199 TokenizeStateLineComment,200 TokenizeStateLineComment,
200 TokenizeStateLineString,201 TokenizeStateLineString,
201 TokenizeStateLineStringEnd,202 TokenizeStateLineStringEnd,
...@@ -594,7 +595,7 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -594,7 +595,7 @@ void tokenize(Buf *buf, Tokenization *out) {
594 break;595 break;
595 case '|':596 case '|':
596 begin_token(&t, TokenIdBinOr);597 begin_token(&t, TokenIdBinOr);
597 t.state = TokenizeStateSawPipe;598 t.state = TokenizeStateSawBar;
598 break;599 break;
599 case '=':600 case '=':
600 begin_token(&t, TokenIdEq);601 begin_token(&t, TokenIdEq);
...@@ -888,13 +889,17 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -888,13 +889,17 @@ void tokenize(Buf *buf, Tokenization *out) {
888 continue;889 continue;
889 }890 }
890 break;891 break;
891 case TokenizeStateSawPipe:892 case TokenizeStateSawBar:
892 switch (c) {893 switch (c) {
893 case '=':894 case '=':
894 set_token_id(&t, t.cur_tok, TokenIdBitOrEq);895 set_token_id(&t, t.cur_tok, TokenIdBitOrEq);
895 end_token(&t);896 end_token(&t);
896 t.state = TokenizeStateStart;897 t.state = TokenizeStateStart;
897 break;898 break;
899 case '|':
900 set_token_id(&t, t.cur_tok, TokenIdBarBar);
901 t.state = TokenizeStateSawBarBar;
902 break;
898 default:903 default:
899 t.pos -= 1;904 t.pos -= 1;
900 end_token(&t);905 end_token(&t);
...@@ -902,6 +907,19 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -902,6 +907,19 @@ void tokenize(Buf *buf, Tokenization *out) {
902 continue;907 continue;
903 }908 }
904 break;909 break;
910 case TokenizeStateSawBarBar:
911 switch (c) {
912 case '=':
913 set_token_id(&t, t.cur_tok, TokenIdBarBarEq);
914 end_token(&t);
915 t.state = TokenizeStateStart;
916 break;
917 default:
918 t.pos -= 1;
919 end_token(&t);
920 t.state = TokenizeStateStart;
921 continue;
922 }
905 case TokenizeStateSawSlash:923 case TokenizeStateSawSlash:
906 switch (c) {924 switch (c) {
907 case '/':925 case '/':
...@@ -1428,7 +1446,7 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -1428,7 +1446,7 @@ void tokenize(Buf *buf, Tokenization *out) {
1428 case TokenizeStateSawDash:1446 case TokenizeStateSawDash:
1429 case TokenizeStateSawAmpersand:1447 case TokenizeStateSawAmpersand:
1430 case TokenizeStateSawCaret:1448 case TokenizeStateSawCaret:
1431 case TokenizeStateSawPipe:1449 case TokenizeStateSawBar:
1432 case TokenizeStateSawEq:1450 case TokenizeStateSawEq:
1433 case TokenizeStateSawBang:1451 case TokenizeStateSawBang:
1434 case TokenizeStateSawLessThan:1452 case TokenizeStateSawLessThan:
...@@ -1443,6 +1461,7 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -1443,6 +1461,7 @@ void tokenize(Buf *buf, Tokenization *out) {
1443 case TokenizeStateSawMinusPercent:1461 case TokenizeStateSawMinusPercent:
1444 case TokenizeStateLineString:1462 case TokenizeStateLineString:
1445 case TokenizeStateLineStringEnd:1463 case TokenizeStateLineStringEnd:
1464 case TokenizeStateSawBarBar:
1446 end_token(&t);1465 end_token(&t);
1447 break;1466 break;
1448 case TokenizeStateSawDotDot:1467 case TokenizeStateSawDotDot:
...@@ -1475,6 +1494,7 @@ const char * token_name(TokenId id) {...@@ -1475,6 +1494,7 @@ const char * token_name(TokenId id) {
1475 case TokenIdArrow: return "->";1494 case TokenIdArrow: return "->";
1476 case TokenIdAtSign: return "@";1495 case TokenIdAtSign: return "@";
1477 case TokenIdBang: return "!";1496 case TokenIdBang: return "!";
1497 case TokenIdBarBar: return "||";
1478 case TokenIdBinOr: return "|";1498 case TokenIdBinOr: return "|";
1479 case TokenIdBinXor: return "^";1499 case TokenIdBinXor: return "^";
1480 case TokenIdBitAndEq: return "&=";1500 case TokenIdBitAndEq: return "&=";
...@@ -1577,6 +1597,7 @@ const char * token_name(TokenId id) {...@@ -1577,6 +1597,7 @@ const char * token_name(TokenId id) {
1577 case TokenIdTimesEq: return "*=";1597 case TokenIdTimesEq: return "*=";
1578 case TokenIdTimesPercent: return "*%";1598 case TokenIdTimesPercent: return "*%";
1579 case TokenIdTimesPercentEq: return "*%=";1599 case TokenIdTimesPercentEq: return "*%=";
1600 case TokenIdBarBarEq: return "||=";
1580 }1601 }
1581 return "(invalid token)";1602 return "(invalid token)";
1582}1603}
src/tokenizer.hpp+2
...@@ -17,6 +17,8 @@ enum TokenId {...@@ -17,6 +17,8 @@ enum TokenId {
17 TokenIdArrow,17 TokenIdArrow,
18 TokenIdAtSign,18 TokenIdAtSign,
19 TokenIdBang,19 TokenIdBang,
20 TokenIdBarBar,
21 TokenIdBarBarEq,
20 TokenIdBinOr,22 TokenIdBinOr,
21 TokenIdBinXor,23 TokenIdBinXor,
22 TokenIdBitAndEq,24 TokenIdBitAndEq,
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>
src/zig_llvm.cpp+4
...@@ -437,6 +437,10 @@ unsigned ZigLLVMTag_DW_structure_type(void) {...@@ -437,6 +437,10 @@ unsigned ZigLLVMTag_DW_structure_type(void) {
437 return dwarf::DW_TAG_structure_type;437 return dwarf::DW_TAG_structure_type;
438}438}
439439
440unsigned ZigLLVMTag_DW_enumeration_type(void) {
441 return dwarf::DW_TAG_enumeration_type;
442}
443
440unsigned ZigLLVMTag_DW_union_type(void) {444unsigned ZigLLVMTag_DW_union_type(void) {
441 return dwarf::DW_TAG_union_type;445 return dwarf::DW_TAG_union_type;
442}446}
src/zig_llvm.h+1
...@@ -133,6 +133,7 @@ ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_signed_char(void);...@@ -133,6 +133,7 @@ ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_signed_char(void);
133ZIG_EXTERN_C unsigned ZigLLVMLang_DW_LANG_C99(void);133ZIG_EXTERN_C unsigned ZigLLVMLang_DW_LANG_C99(void);
134ZIG_EXTERN_C unsigned ZigLLVMTag_DW_variable(void);134ZIG_EXTERN_C unsigned ZigLLVMTag_DW_variable(void);
135ZIG_EXTERN_C unsigned ZigLLVMTag_DW_structure_type(void);135ZIG_EXTERN_C unsigned ZigLLVMTag_DW_structure_type(void);
136ZIG_EXTERN_C unsigned ZigLLVMTag_DW_enumeration_type(void);
136ZIG_EXTERN_C unsigned ZigLLVMTag_DW_union_type(void);137ZIG_EXTERN_C unsigned ZigLLVMTag_DW_union_type(void);
137138
138ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved);139ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved);
std/array_list.zig+7-7
...@@ -63,7 +63,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{...@@ -63,7 +63,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
63 return result;63 return result;
64 }64 }
6565
66 pub fn insert(l: &Self, n: usize, item: &const T) %void {66 pub fn insert(l: &Self, n: usize, item: &const T) !void {
67 try l.ensureCapacity(l.len + 1);67 try l.ensureCapacity(l.len + 1);
68 l.len += 1;68 l.len += 1;
6969
...@@ -71,7 +71,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{...@@ -71,7 +71,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
71 l.items[n] = *item;71 l.items[n] = *item;
72 }72 }
7373
74 pub fn insertSlice(l: &Self, n: usize, items: []align(A) const T) %void {74 pub fn insertSlice(l: &Self, n: usize, items: []align(A) const T) !void {
75 try l.ensureCapacity(l.len + items.len);75 try l.ensureCapacity(l.len + items.len);
76 l.len += items.len;76 l.len += items.len;
7777
...@@ -79,18 +79,18 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{...@@ -79,18 +79,18 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
79 mem.copy(T, l.items[n..n+items.len], items);79 mem.copy(T, l.items[n..n+items.len], items);
80 }80 }
8181
82 pub fn append(l: &Self, item: &const T) %void {82 pub fn append(l: &Self, item: &const T) !void {
83 const new_item_ptr = try l.addOne();83 const new_item_ptr = try l.addOne();
84 *new_item_ptr = *item;84 *new_item_ptr = *item;
85 }85 }
8686
87 pub fn appendSlice(l: &Self, items: []align(A) const T) %void {87 pub fn appendSlice(l: &Self, items: []align(A) const T) !void {
88 try l.ensureCapacity(l.len + items.len);88 try l.ensureCapacity(l.len + items.len);
89 mem.copy(T, l.items[l.len..], items);89 mem.copy(T, l.items[l.len..], items);
90 l.len += items.len;90 l.len += items.len;
91 }91 }
9292
93 pub fn resize(l: &Self, new_len: usize) %void {93 pub fn resize(l: &Self, new_len: usize) !void {
94 try l.ensureCapacity(new_len);94 try l.ensureCapacity(new_len);
95 l.len = new_len;95 l.len = new_len;
96 }96 }
...@@ -100,7 +100,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{...@@ -100,7 +100,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
100 l.len = new_len;100 l.len = new_len;
101 }101 }
102102
103 pub fn ensureCapacity(l: &Self, new_capacity: usize) %void {103 pub fn ensureCapacity(l: &Self, new_capacity: usize) !void {
104 var better_capacity = l.items.len;104 var better_capacity = l.items.len;
105 if (better_capacity >= new_capacity) return;105 if (better_capacity >= new_capacity) return;
106 while (true) {106 while (true) {
...@@ -110,7 +110,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{...@@ -110,7 +110,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
110 l.items = try l.allocator.alignedRealloc(T, A, l.items, better_capacity);110 l.items = try l.allocator.alignedRealloc(T, A, l.items, better_capacity);
111 }111 }
112112
113 pub fn addOne(l: &Self) %&T {113 pub fn addOne(l: &Self) !&T {
114 const new_length = l.len + 1;114 const new_length = l.len + 1;
115 try l.ensureCapacity(new_length);115 try l.ensureCapacity(new_length);
116 const result = &l.items[l.len];116 const result = &l.items[l.len];
std/base64.zig+11-16
...@@ -79,8 +79,6 @@ pub const Base64Encoder = struct {...@@ -79,8 +79,6 @@ pub const Base64Encoder = struct {
79};79};
8080
81pub const standard_decoder = Base64Decoder.init(standard_alphabet_chars, standard_pad_char);81pub const standard_decoder = Base64Decoder.init(standard_alphabet_chars, standard_pad_char);
82error InvalidPadding;
83error InvalidCharacter;
8482
85pub const Base64Decoder = struct {83pub const Base64Decoder = struct {
86 /// e.g. 'A' => 0.84 /// e.g. 'A' => 0.
...@@ -111,7 +109,7 @@ pub const Base64Decoder = struct {...@@ -111,7 +109,7 @@ pub const Base64Decoder = struct {
111 }109 }
112110
113 /// If the encoded buffer is detected to be invalid, returns error.InvalidPadding.111 /// If the encoded buffer is detected to be invalid, returns error.InvalidPadding.
114 pub fn calcSize(decoder: &const Base64Decoder, source: []const u8) %usize {112 pub fn calcSize(decoder: &const Base64Decoder, source: []const u8) !usize {
115 if (source.len % 4 != 0) return error.InvalidPadding;113 if (source.len % 4 != 0) return error.InvalidPadding;
116 return calcDecodedSizeExactUnsafe(source, decoder.pad_char);114 return calcDecodedSizeExactUnsafe(source, decoder.pad_char);
117 }115 }
...@@ -119,7 +117,7 @@ pub const Base64Decoder = struct {...@@ -119,7 +117,7 @@ pub const Base64Decoder = struct {
119 /// dest.len must be what you get from ::calcSize.117 /// dest.len must be what you get from ::calcSize.
120 /// invalid characters result in error.InvalidCharacter.118 /// invalid characters result in error.InvalidCharacter.
121 /// invalid padding results in error.InvalidPadding.119 /// invalid padding results in error.InvalidPadding.
122 pub fn decode(decoder: &const Base64Decoder, dest: []u8, source: []const u8) %void {120 pub fn decode(decoder: &const Base64Decoder, dest: []u8, source: []const u8) !void {
123 assert(dest.len == (decoder.calcSize(source) catch unreachable));121 assert(dest.len == (decoder.calcSize(source) catch unreachable));
124 assert(source.len % 4 == 0);122 assert(source.len % 4 == 0);
125123
...@@ -163,8 +161,6 @@ pub const Base64Decoder = struct {...@@ -163,8 +161,6 @@ pub const Base64Decoder = struct {
163 }161 }
164};162};
165163
166error OutputTooSmall;
167
168pub const Base64DecoderWithIgnore = struct {164pub const Base64DecoderWithIgnore = struct {
169 decoder: Base64Decoder,165 decoder: Base64Decoder,
170 char_is_ignored: [256]bool,166 char_is_ignored: [256]bool,
...@@ -185,7 +181,7 @@ pub const Base64DecoderWithIgnore = struct {...@@ -185,7 +181,7 @@ pub const Base64DecoderWithIgnore = struct {
185 }181 }
186182
187 /// If no characters end up being ignored or padding, this will be the exact decoded size.183 /// If no characters end up being ignored or padding, this will be the exact decoded size.
188 pub fn calcSizeUpperBound(encoded_len: usize) %usize {184 pub fn calcSizeUpperBound(encoded_len: usize) usize {
189 return @divTrunc(encoded_len, 4) * 3;185 return @divTrunc(encoded_len, 4) * 3;
190 }186 }
191187
...@@ -193,7 +189,7 @@ pub const Base64DecoderWithIgnore = struct {...@@ -193,7 +189,7 @@ pub const Base64DecoderWithIgnore = struct {
193 /// Invalid padding results in error.InvalidPadding.189 /// Invalid padding results in error.InvalidPadding.
194 /// Decoding more data than can fit in dest results in error.OutputTooSmall. See also ::calcSizeUpperBound.190 /// Decoding more data than can fit in dest results in error.OutputTooSmall. See also ::calcSizeUpperBound.
195 /// Returns the number of bytes writen to dest.191 /// Returns the number of bytes writen to dest.
196 pub fn decode(decoder_with_ignore: &const Base64DecoderWithIgnore, dest: []u8, source: []const u8) %usize {192 pub fn decode(decoder_with_ignore: &const Base64DecoderWithIgnore, dest: []u8, source: []const u8) !usize {
197 const decoder = &decoder_with_ignore.decoder;193 const decoder = &decoder_with_ignore.decoder;
198194
199 var src_cursor: usize = 0;195 var src_cursor: usize = 0;
...@@ -378,7 +374,7 @@ test "base64" {...@@ -378,7 +374,7 @@ test "base64" {
378 comptime (testBase64() catch unreachable);374 comptime (testBase64() catch unreachable);
379}375}
380376
381fn testBase64() %void {377fn testBase64() !void {
382 try testAllApis("", "");378 try testAllApis("", "");
383 try testAllApis("f", "Zg==");379 try testAllApis("f", "Zg==");
384 try testAllApis("fo", "Zm8=");380 try testAllApis("fo", "Zm8=");
...@@ -412,7 +408,7 @@ fn testBase64() %void {...@@ -412,7 +408,7 @@ fn testBase64() %void {
412 try testOutputTooSmallError("AAAAAA==");408 try testOutputTooSmallError("AAAAAA==");
413}409}
414410
415fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) %void {411fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void {
416 // Base64Encoder412 // Base64Encoder
417 {413 {
418 var buffer: [0x100]u8 = undefined;414 var buffer: [0x100]u8 = undefined;
...@@ -434,7 +430,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) %void...@@ -434,7 +430,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) %void
434 const standard_decoder_ignore_nothing = Base64DecoderWithIgnore.init(430 const standard_decoder_ignore_nothing = Base64DecoderWithIgnore.init(
435 standard_alphabet_chars, standard_pad_char, "");431 standard_alphabet_chars, standard_pad_char, "");
436 var buffer: [0x100]u8 = undefined;432 var buffer: [0x100]u8 = undefined;
437 var decoded = buffer[0..try Base64DecoderWithIgnore.calcSizeUpperBound(expected_encoded.len)];433 var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(expected_encoded.len)];
438 var written = try standard_decoder_ignore_nothing.decode(decoded, expected_encoded);434 var written = try standard_decoder_ignore_nothing.decode(decoded, expected_encoded);
439 assert(written <= decoded.len);435 assert(written <= decoded.len);
440 assert(mem.eql(u8, decoded[0..written], expected_decoded));436 assert(mem.eql(u8, decoded[0..written], expected_decoded));
...@@ -449,17 +445,16 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) %void...@@ -449,17 +445,16 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) %void
449 }445 }
450}446}
451447
452fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) %void {448fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) !void {
453 const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(449 const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
454 standard_alphabet_chars, standard_pad_char, " ");450 standard_alphabet_chars, standard_pad_char, " ");
455 var buffer: [0x100]u8 = undefined;451 var buffer: [0x100]u8 = undefined;
456 var decoded = buffer[0..try Base64DecoderWithIgnore.calcSizeUpperBound(encoded.len)];452 var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(encoded.len)];
457 var written = try standard_decoder_ignore_space.decode(decoded, encoded);453 var written = try standard_decoder_ignore_space.decode(decoded, encoded);
458 assert(mem.eql(u8, decoded[0..written], expected_decoded));454 assert(mem.eql(u8, decoded[0..written], expected_decoded));
459}455}
460456
461error ExpectedError;457fn testError(encoded: []const u8, expected_err: error) !void {
462fn testError(encoded: []const u8, expected_err: error) %void {
463 const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(458 const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
464 standard_alphabet_chars, standard_pad_char, " ");459 standard_alphabet_chars, standard_pad_char, " ");
465 var buffer: [0x100]u8 = undefined;460 var buffer: [0x100]u8 = undefined;
...@@ -475,7 +470,7 @@ fn testError(encoded: []const u8, expected_err: error) %void {...@@ -475,7 +470,7 @@ fn testError(encoded: []const u8, expected_err: error) %void {
475 } else |err| if (err != expected_err) return err;470 } else |err| if (err != expected_err) return err;
476}471}
477472
478fn testOutputTooSmallError(encoded: []const u8) %void {473fn testOutputTooSmallError(encoded: []const u8) !void {
479 const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(474 const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
480 standard_alphabet_chars, standard_pad_char, " ");475 standard_alphabet_chars, standard_pad_char, " ");
481 var buffer: [0x100]u8 = undefined;476 var buffer: [0x100]u8 = undefined;
std/buf_map.zig+2-2
...@@ -27,7 +27,7 @@ pub const BufMap = struct {...@@ -27,7 +27,7 @@ pub const BufMap = struct {
27 self.hash_map.deinit();27 self.hash_map.deinit();
28 }28 }
2929
30 pub fn set(self: &BufMap, key: []const u8, value: []const u8) %void {30 pub fn set(self: &BufMap, key: []const u8, value: []const u8) !void {
31 if (self.hash_map.get(key)) |entry| {31 if (self.hash_map.get(key)) |entry| {
32 const value_copy = try self.copy(value);32 const value_copy = try self.copy(value);
33 errdefer self.free(value_copy);33 errdefer self.free(value_copy);
...@@ -67,7 +67,7 @@ pub const BufMap = struct {...@@ -67,7 +67,7 @@ pub const BufMap = struct {
67 self.hash_map.allocator.free(mut_value);67 self.hash_map.allocator.free(mut_value);
68 }68 }
6969
70 fn copy(self: &BufMap, value: []const u8) %[]const u8 {70 fn copy(self: &BufMap, value: []const u8) ![]const u8 {
71 const result = try self.hash_map.allocator.alloc(u8, value.len);71 const result = try self.hash_map.allocator.alloc(u8, value.len);
72 mem.copy(u8, result, value);72 mem.copy(u8, result, value);
73 return result;73 return result;
std/buf_set.zig+2-2
...@@ -24,7 +24,7 @@ pub const BufSet = struct {...@@ -24,7 +24,7 @@ pub const BufSet = struct {
24 self.hash_map.deinit();24 self.hash_map.deinit();
25 }25 }
2626
27 pub fn put(self: &BufSet, key: []const u8) %void {27 pub fn put(self: &BufSet, key: []const u8) !void {
28 if (self.hash_map.get(key) == null) {28 if (self.hash_map.get(key) == null) {
29 const key_copy = try self.copy(key);29 const key_copy = try self.copy(key);
30 errdefer self.free(key_copy);30 errdefer self.free(key_copy);
...@@ -55,7 +55,7 @@ pub const BufSet = struct {...@@ -55,7 +55,7 @@ pub const BufSet = struct {
55 self.hash_map.allocator.free(mut_value);55 self.hash_map.allocator.free(mut_value);
56 }56 }
5757
58 fn copy(self: &BufSet, value: []const u8) %[]const u8 {58 fn copy(self: &BufSet, value: []const u8) ![]const u8 {
59 const result = try self.hash_map.allocator.alloc(u8, value.len);59 const result = try self.hash_map.allocator.alloc(u8, value.len);
60 mem.copy(u8, result, value);60 mem.copy(u8, result, value);
61 return result;61 return result;
std/buffer.zig+9-9
...@@ -12,14 +12,14 @@ pub const Buffer = struct {...@@ -12,14 +12,14 @@ pub const Buffer = struct {
12 list: ArrayList(u8),12 list: ArrayList(u8),
1313
14 /// Must deinitialize with deinit.14 /// Must deinitialize with deinit.
15 pub fn init(allocator: &Allocator, m: []const u8) %Buffer {15 pub fn init(allocator: &Allocator, m: []const u8) !Buffer {
16 var self = try initSize(allocator, m.len);16 var self = try initSize(allocator, m.len);
17 mem.copy(u8, self.list.items, m);17 mem.copy(u8, self.list.items, m);
18 return self;18 return self;
19 }19 }
2020
21 /// Must deinitialize with deinit.21 /// Must deinitialize with deinit.
22 pub fn initSize(allocator: &Allocator, size: usize) %Buffer {22 pub fn initSize(allocator: &Allocator, size: usize) !Buffer {
23 var self = initNull(allocator);23 var self = initNull(allocator);
24 try self.resize(size);24 try self.resize(size);
25 return self;25 return self;
...@@ -37,7 +37,7 @@ pub const Buffer = struct {...@@ -37,7 +37,7 @@ pub const Buffer = struct {
37 }37 }
3838
39 /// Must deinitialize with deinit.39 /// Must deinitialize with deinit.
40 pub fn initFromBuffer(buffer: &const Buffer) %Buffer {40 pub fn initFromBuffer(buffer: &const Buffer) !Buffer {
41 return Buffer.init(buffer.list.allocator, buffer.toSliceConst());41 return Buffer.init(buffer.list.allocator, buffer.toSliceConst());
42 }42 }
4343
...@@ -80,7 +80,7 @@ pub const Buffer = struct {...@@ -80,7 +80,7 @@ pub const Buffer = struct {
80 self.list.items[self.len()] = 0;80 self.list.items[self.len()] = 0;
81 }81 }
8282
83 pub fn resize(self: &Buffer, new_len: usize) %void {83 pub fn resize(self: &Buffer, new_len: usize) !void {
84 try self.list.resize(new_len + 1);84 try self.list.resize(new_len + 1);
85 self.list.items[self.len()] = 0;85 self.list.items[self.len()] = 0;
86 }86 }
...@@ -93,24 +93,24 @@ pub const Buffer = struct {...@@ -93,24 +93,24 @@ pub const Buffer = struct {
93 return self.list.len - 1;93 return self.list.len - 1;
94 }94 }
9595
96 pub fn append(self: &Buffer, m: []const u8) %void {96 pub fn append(self: &Buffer, m: []const u8) !void {
97 const old_len = self.len();97 const old_len = self.len();
98 try self.resize(old_len + m.len);98 try self.resize(old_len + m.len);
99 mem.copy(u8, self.list.toSlice()[old_len..], m);99 mem.copy(u8, self.list.toSlice()[old_len..], m);
100 }100 }
101101
102 // TODO: remove, use OutStream for this102 // TODO: remove, use OutStream for this
103 pub fn appendFormat(self: &Buffer, comptime format: []const u8, args: ...) %void {103 pub fn appendFormat(self: &Buffer, comptime format: []const u8, args: ...) !void {
104 return fmt.format(self, append, format, args);104 return fmt.format(self, append, format, args);
105 }105 }
106106
107 // TODO: remove, use OutStream for this107 // TODO: remove, use OutStream for this
108 pub fn appendByte(self: &Buffer, byte: u8) %void {108 pub fn appendByte(self: &Buffer, byte: u8) !void {
109 return self.appendByteNTimes(byte, 1);109 return self.appendByteNTimes(byte, 1);
110 }110 }
111111
112 // TODO: remove, use OutStream for this112 // TODO: remove, use OutStream for this
113 pub fn appendByteNTimes(self: &Buffer, byte: u8, count: usize) %void {113 pub fn appendByteNTimes(self: &Buffer, byte: u8, count: usize) !void {
114 var prev_size: usize = self.len();114 var prev_size: usize = self.len();
115 const new_size = prev_size + count;115 const new_size = prev_size + count;
116 try self.resize(new_size);116 try self.resize(new_size);
...@@ -137,7 +137,7 @@ pub const Buffer = struct {...@@ -137,7 +137,7 @@ pub const Buffer = struct {
137 return mem.eql(u8, self.list.items[start..l], m);137 return mem.eql(u8, self.list.items[start..l], m);
138 }138 }
139139
140 pub fn replaceContents(self: &const Buffer, m: []const u8) %void {140 pub fn replaceContents(self: &const Buffer, m: []const u8) !void {
141 try self.resize(m.len);141 try self.resize(m.len);
142 mem.copy(u8, self.list.toSlice(), m);142 mem.copy(u8, self.list.toSlice(), m);
143 }143 }
std/build.zig+26-33
...@@ -15,13 +15,6 @@ const BufSet = std.BufSet;...@@ -15,13 +15,6 @@ const BufSet = std.BufSet;
15const BufMap = std.BufMap;15const BufMap = std.BufMap;
16const fmt_lib = std.fmt;16const fmt_lib = std.fmt;
1717
18error ExtraArg;
19error UncleanExit;
20error InvalidStepName;
21error DependencyLoopDetected;
22error NoCompilerFound;
23error NeedAnObject;
24
25pub const Builder = struct {18pub const Builder = struct {
26 uninstall_tls: TopLevelStep,19 uninstall_tls: TopLevelStep,
27 install_tls: TopLevelStep,20 install_tls: TopLevelStep,
...@@ -242,7 +235,7 @@ pub const Builder = struct {...@@ -242,7 +235,7 @@ pub const Builder = struct {
242 self.lib_paths.append(path) catch unreachable;235 self.lib_paths.append(path) catch unreachable;
243 }236 }
244237
245 pub fn make(self: &Builder, step_names: []const []const u8) %void {238 pub fn make(self: &Builder, step_names: []const []const u8) !void {
246 var wanted_steps = ArrayList(&Step).init(self.allocator);239 var wanted_steps = ArrayList(&Step).init(self.allocator);
247 defer wanted_steps.deinit();240 defer wanted_steps.deinit();
248241
...@@ -278,7 +271,7 @@ pub const Builder = struct {...@@ -278,7 +271,7 @@ pub const Builder = struct {
278 return &self.uninstall_tls.step;271 return &self.uninstall_tls.step;
279 }272 }
280273
281 fn makeUninstall(uninstall_step: &Step) %void {274 fn makeUninstall(uninstall_step: &Step) error!void {
282 const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step);275 const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step);
283 const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls);276 const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls);
284277
...@@ -292,7 +285,7 @@ pub const Builder = struct {...@@ -292,7 +285,7 @@ pub const Builder = struct {
292 // TODO remove empty directories285 // TODO remove empty directories
293 }286 }
294287
295 fn makeOneStep(self: &Builder, s: &Step) %void {288 fn makeOneStep(self: &Builder, s: &Step) error!void {
296 if (s.loop_flag) {289 if (s.loop_flag) {
297 warn("Dependency loop detected:\n {}\n", s.name);290 warn("Dependency loop detected:\n {}\n", s.name);
298 return error.DependencyLoopDetected;291 return error.DependencyLoopDetected;
...@@ -313,7 +306,7 @@ pub const Builder = struct {...@@ -313,7 +306,7 @@ pub const Builder = struct {
313 try s.make();306 try s.make();
314 }307 }
315308
316 fn getTopLevelStepByName(self: &Builder, name: []const u8) %&Step {309 fn getTopLevelStepByName(self: &Builder, name: []const u8) !&Step {
317 for (self.top_level_steps.toSliceConst()) |top_level_step| {310 for (self.top_level_steps.toSliceConst()) |top_level_step| {
318 if (mem.eql(u8, top_level_step.step.name, name)) {311 if (mem.eql(u8, top_level_step.step.name, name)) {
319 return &top_level_step.step;312 return &top_level_step.step;
...@@ -548,7 +541,7 @@ pub const Builder = struct {...@@ -548,7 +541,7 @@ pub const Builder = struct {
548 return self.invalid_user_input;541 return self.invalid_user_input;
549 }542 }
550543
551 fn spawnChild(self: &Builder, argv: []const []const u8) %void {544 fn spawnChild(self: &Builder, argv: []const []const u8) !void {
552 return self.spawnChildEnvMap(null, &self.env_map, argv);545 return self.spawnChildEnvMap(null, &self.env_map, argv);
553 }546 }
554547
...@@ -561,7 +554,7 @@ pub const Builder = struct {...@@ -561,7 +554,7 @@ pub const Builder = struct {
561 }554 }
562555
563 fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,556 fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
564 argv: []const []const u8) %void557 argv: []const []const u8) !void
565 {558 {
566 if (self.verbose) {559 if (self.verbose) {
567 printCmd(cwd, argv);560 printCmd(cwd, argv);
...@@ -595,7 +588,7 @@ pub const Builder = struct {...@@ -595,7 +588,7 @@ pub const Builder = struct {
595 }588 }
596 }589 }
597590
598 pub fn makePath(self: &Builder, path: []const u8) %void {591 pub fn makePath(self: &Builder, path: []const u8) !void {
599 os.makePath(self.allocator, self.pathFromRoot(path)) catch |err| {592 os.makePath(self.allocator, self.pathFromRoot(path)) catch |err| {
600 warn("Unable to create path {}: {}\n", path, @errorName(err));593 warn("Unable to create path {}: {}\n", path, @errorName(err));
601 return err;594 return err;
...@@ -630,11 +623,11 @@ pub const Builder = struct {...@@ -630,11 +623,11 @@ pub const Builder = struct {
630 self.installed_files.append(full_path) catch unreachable;623 self.installed_files.append(full_path) catch unreachable;
631 }624 }
632625
633 fn copyFile(self: &Builder, source_path: []const u8, dest_path: []const u8) %void {626 fn copyFile(self: &Builder, source_path: []const u8, dest_path: []const u8) !void {
634 return self.copyFileMode(source_path, dest_path, 0o666);627 return self.copyFileMode(source_path, dest_path, 0o666);
635 }628 }
636629
637 fn copyFileMode(self: &Builder, source_path: []const u8, dest_path: []const u8, mode: usize) %void {630 fn copyFileMode(self: &Builder, source_path: []const u8, dest_path: []const u8, mode: usize) !void {
638 if (self.verbose) {631 if (self.verbose) {
639 warn("cp {} {}\n", source_path, dest_path);632 warn("cp {} {}\n", source_path, dest_path);
640 }633 }
...@@ -672,7 +665,7 @@ pub const Builder = struct {...@@ -672,7 +665,7 @@ pub const Builder = struct {
672 }665 }
673 }666 }
674667
675 pub fn findProgram(self: &Builder, names: []const []const u8, paths: []const []const u8) %[]const u8 {668 pub fn findProgram(self: &Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {
676 // TODO report error for ambiguous situations669 // TODO report error for ambiguous situations
677 const exe_extension = (Target { .Native = {}}).exeFileExt();670 const exe_extension = (Target { .Native = {}}).exeFileExt();
678 for (self.search_prefixes.toSliceConst()) |search_prefix| {671 for (self.search_prefixes.toSliceConst()) |search_prefix| {
...@@ -721,7 +714,7 @@ pub const Builder = struct {...@@ -721,7 +714,7 @@ pub const Builder = struct {
721 return error.FileNotFound;714 return error.FileNotFound;
722 }715 }
723716
724 pub fn exec(self: &Builder, argv: []const []const u8) %[]u8 {717 pub fn exec(self: &Builder, argv: []const []const u8) ![]u8 {
725 const max_output_size = 100 * 1024;718 const max_output_size = 100 * 1024;
726 const result = try os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size);719 const result = try os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size);
727 switch (result.term) {720 switch (result.term) {
...@@ -1180,12 +1173,12 @@ pub const LibExeObjStep = struct {...@@ -1180,12 +1173,12 @@ pub const LibExeObjStep = struct {
1180 self.disable_libc = disable;1173 self.disable_libc = disable;
1181 }1174 }
11821175
1183 fn make(step: &Step) %void {1176 fn make(step: &Step) !void {
1184 const self = @fieldParentPtr(LibExeObjStep, "step", step);1177 const self = @fieldParentPtr(LibExeObjStep, "step", step);
1185 return if (self.is_zig) self.makeZig() else self.makeC();1178 return if (self.is_zig) self.makeZig() else self.makeC();
1186 }1179 }
11871180
1188 fn makeZig(self: &LibExeObjStep) %void {1181 fn makeZig(self: &LibExeObjStep) !void {
1189 const builder = self.builder;1182 const builder = self.builder;
11901183
1191 assert(self.is_zig);1184 assert(self.is_zig);
...@@ -1396,7 +1389,7 @@ pub const LibExeObjStep = struct {...@@ -1396,7 +1389,7 @@ pub const LibExeObjStep = struct {
1396 }1389 }
1397 }1390 }
13981391
1399 fn makeC(self: &LibExeObjStep) %void {1392 fn makeC(self: &LibExeObjStep) !void {
1400 const builder = self.builder;1393 const builder = self.builder;
14011394
1402 const cc = builder.getCCExe();1395 const cc = builder.getCCExe();
...@@ -1687,7 +1680,7 @@ pub const TestStep = struct {...@@ -1687,7 +1680,7 @@ pub const TestStep = struct {
1687 self.exec_cmd_args = args;1680 self.exec_cmd_args = args;
1688 }1681 }
16891682
1690 fn make(step: &Step) %void {1683 fn make(step: &Step) !void {
1691 const self = @fieldParentPtr(TestStep, "step", step);1684 const self = @fieldParentPtr(TestStep, "step", step);
1692 const builder = self.builder;1685 const builder = self.builder;
16931686
...@@ -1796,7 +1789,7 @@ pub const CommandStep = struct {...@@ -1796,7 +1789,7 @@ pub const CommandStep = struct {
1796 return self;1789 return self;
1797 }1790 }
17981791
1799 fn make(step: &Step) %void {1792 fn make(step: &Step) !void {
1800 const self = @fieldParentPtr(CommandStep, "step", step);1793 const self = @fieldParentPtr(CommandStep, "step", step);
18011794
1802 const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else self.builder.build_root;1795 const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else self.builder.build_root;
...@@ -1836,7 +1829,7 @@ const InstallArtifactStep = struct {...@@ -1836,7 +1829,7 @@ const InstallArtifactStep = struct {
1836 return self;1829 return self;
1837 }1830 }
18381831
1839 fn make(step: &Step) %void {1832 fn make(step: &Step) !void {
1840 const self = @fieldParentPtr(Self, "step", step);1833 const self = @fieldParentPtr(Self, "step", step);
1841 const builder = self.builder;1834 const builder = self.builder;
18421835
...@@ -1868,7 +1861,7 @@ pub const InstallFileStep = struct {...@@ -1868,7 +1861,7 @@ pub const InstallFileStep = struct {
1868 };1861 };
1869 }1862 }
18701863
1871 fn make(step: &Step) %void {1864 fn make(step: &Step) !void {
1872 const self = @fieldParentPtr(InstallFileStep, "step", step);1865 const self = @fieldParentPtr(InstallFileStep, "step", step);
1873 try self.builder.copyFile(self.src_path, self.dest_path);1866 try self.builder.copyFile(self.src_path, self.dest_path);
1874 }1867 }
...@@ -1889,7 +1882,7 @@ pub const WriteFileStep = struct {...@@ -1889,7 +1882,7 @@ pub const WriteFileStep = struct {
1889 };1882 };
1890 }1883 }
18911884
1892 fn make(step: &Step) %void {1885 fn make(step: &Step) !void {
1893 const self = @fieldParentPtr(WriteFileStep, "step", step);1886 const self = @fieldParentPtr(WriteFileStep, "step", step);
1894 const full_path = self.builder.pathFromRoot(self.file_path);1887 const full_path = self.builder.pathFromRoot(self.file_path);
1895 const full_path_dir = os.path.dirname(full_path);1888 const full_path_dir = os.path.dirname(full_path);
...@@ -1917,7 +1910,7 @@ pub const LogStep = struct {...@@ -1917,7 +1910,7 @@ pub const LogStep = struct {
1917 };1910 };
1918 }1911 }
19191912
1920 fn make(step: &Step) %void {1913 fn make(step: &Step) error!void {
1921 const self = @fieldParentPtr(LogStep, "step", step);1914 const self = @fieldParentPtr(LogStep, "step", step);
1922 warn("{}", self.data);1915 warn("{}", self.data);
1923 }1916 }
...@@ -1936,7 +1929,7 @@ pub const RemoveDirStep = struct {...@@ -1936,7 +1929,7 @@ pub const RemoveDirStep = struct {
1936 };1929 };
1937 }1930 }
19381931
1939 fn make(step: &Step) %void {1932 fn make(step: &Step) !void {
1940 const self = @fieldParentPtr(RemoveDirStep, "step", step);1933 const self = @fieldParentPtr(RemoveDirStep, "step", step);
19411934
1942 const full_path = self.builder.pathFromRoot(self.dir_path);1935 const full_path = self.builder.pathFromRoot(self.dir_path);
...@@ -1949,12 +1942,12 @@ pub const RemoveDirStep = struct {...@@ -1949,12 +1942,12 @@ pub const RemoveDirStep = struct {
19491942
1950pub const Step = struct {1943pub const Step = struct {
1951 name: []const u8,1944 name: []const u8,
1952 makeFn: fn(self: &Step) %void,1945 makeFn: fn(self: &Step) error!void,
1953 dependencies: ArrayList(&Step),1946 dependencies: ArrayList(&Step),
1954 loop_flag: bool,1947 loop_flag: bool,
1955 done_flag: bool,1948 done_flag: bool,
19561949
1957 pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)%void) Step {1950 pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)error!void) Step {
1958 return Step {1951 return Step {
1959 .name = name,1952 .name = name,
1960 .makeFn = makeFn,1953 .makeFn = makeFn,
...@@ -1967,7 +1960,7 @@ pub const Step = struct {...@@ -1967,7 +1960,7 @@ pub const Step = struct {
1967 return init(name, allocator, makeNoOp);1960 return init(name, allocator, makeNoOp);
1968 }1961 }
19691962
1970 pub fn make(self: &Step) %void {1963 pub fn make(self: &Step) !void {
1971 if (self.done_flag)1964 if (self.done_flag)
1972 return;1965 return;
19731966
...@@ -1979,11 +1972,11 @@ pub const Step = struct {...@@ -1979,11 +1972,11 @@ pub const Step = struct {
1979 self.dependencies.append(other) catch unreachable;1972 self.dependencies.append(other) catch unreachable;
1980 }1973 }
19811974
1982 fn makeNoOp(self: &Step) %void {}1975 fn makeNoOp(self: &Step) error!void {}
1983};1976};
19841977
1985fn 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,
1986 filename_name_only: []const u8) %void1979 filename_name_only: []const u8) !void
1987{1980{
1988 const out_dir = os.path.dirname(output_path);1981 const out_dir = os.path.dirname(output_path);
1989 const out_basename = os.path.basename(output_path);1982 const out_basename = os.path.basename(output_path);
std/c/index.zig+1-1
...@@ -20,7 +20,7 @@ pub extern "c" fn open(path: &const u8, oflag: c_int, ...) c_int;...@@ -20,7 +20,7 @@ pub extern "c" fn open(path: &const u8, oflag: c_int, ...) c_int;
20pub extern "c" fn raise(sig: c_int) c_int;20pub extern "c" fn raise(sig: c_int) c_int;
21pub extern "c" fn read(fd: c_int, buf: &c_void, nbyte: usize) isize;21pub extern "c" fn read(fd: c_int, buf: &c_void, nbyte: usize) isize;
22pub extern "c" fn stat(noalias path: &const u8, noalias buf: &Stat) c_int;22pub extern "c" fn stat(noalias path: &const u8, noalias buf: &Stat) c_int;
23pub extern "c" fn write(fd: c_int, buf: &const c_void, nbyte: usize) c_int;23pub extern "c" fn write(fd: c_int, buf: &const c_void, nbyte: usize) isize;
24pub extern "c" fn mmap(addr: ?&c_void, len: usize, prot: c_int, flags: c_int,24pub extern "c" fn mmap(addr: ?&c_void, len: usize, prot: c_int, flags: c_int,
25 fd: c_int, offset: isize) ?&c_void;25 fd: c_int, offset: isize) ?&c_void;
26pub extern "c" fn munmap(addr: &c_void, len: usize) c_int;26pub extern "c" fn munmap(addr: &c_void, len: usize) c_int;
std/crypto/throughput_test.zig+1-1
...@@ -18,7 +18,7 @@ const c = @cImport({...@@ -18,7 +18,7 @@ const c = @cImport({
1818
19const Mb = 1024 * 1024;19const Mb = 1024 * 1024;
2020
21pub fn main() %void {21pub fn main() !void {
22 var stdout_file = try std.io.getStdOut();22 var stdout_file = try std.io.getStdOut();
23 var stdout_out_stream = std.io.FileOutStream.init(&stdout_file);23 var stdout_out_stream = std.io.FileOutStream.init(&stdout_file);
24 const stdout = &stdout_out_stream.stream;24 const stdout = &stdout_out_stream.stream;
std/cstr.zig+2-2
...@@ -42,7 +42,7 @@ fn testCStrFnsImpl() void {...@@ -42,7 +42,7 @@ fn testCStrFnsImpl() void {
42/// Returns a mutable slice with exactly the same size which is guaranteed to42/// Returns a mutable slice with exactly the same size which is guaranteed to
43/// have a null byte after it.43/// have a null byte after it.
44/// Caller owns the returned memory.44/// Caller owns the returned memory.
45pub fn addNullByte(allocator: &mem.Allocator, slice: []const u8) %[]u8 {45pub fn addNullByte(allocator: &mem.Allocator, slice: []const u8) ![]u8 {
46 const result = try allocator.alloc(u8, slice.len + 1);46 const result = try allocator.alloc(u8, slice.len + 1);
47 mem.copy(u8, result, slice);47 mem.copy(u8, result, slice);
48 result[slice.len] = 0;48 result[slice.len] = 0;
...@@ -56,7 +56,7 @@ pub const NullTerminated2DArray = struct {...@@ -56,7 +56,7 @@ pub const NullTerminated2DArray = struct {
5656
57 /// Takes N lists of strings, concatenates the lists together, and adds a null terminator57 /// Takes N lists of strings, concatenates the lists together, and adds a null terminator
58 /// Caller must deinit result58 /// Caller must deinit result
59 pub fn fromSlices(allocator: &mem.Allocator, slices: []const []const []const u8) %NullTerminated2DArray {59 pub fn fromSlices(allocator: &mem.Allocator, slices: []const []const []const u8) !NullTerminated2DArray {
60 var new_len: usize = 1; // 1 for the list null60 var new_len: usize = 1; // 1 for the list null
61 var byte_count: usize = 0;61 var byte_count: usize = 0;
62 for (slices) |slice| {62 for (slices) |slice| {
std/debug/failing_allocator.zig+2-2
...@@ -28,7 +28,7 @@ pub const FailingAllocator = struct {...@@ -28,7 +28,7 @@ pub const FailingAllocator = struct {
28 };28 };
29 }29 }
3030
31 fn alloc(allocator: &mem.Allocator, n: usize, alignment: u29) %[]u8 {31 fn alloc(allocator: &mem.Allocator, n: usize, alignment: u29) ![]u8 {
32 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);32 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
33 if (self.index == self.fail_index) {33 if (self.index == self.fail_index) {
34 return error.OutOfMemory;34 return error.OutOfMemory;
...@@ -39,7 +39,7 @@ pub const FailingAllocator = struct {...@@ -39,7 +39,7 @@ pub const FailingAllocator = struct {
39 return result;39 return result;
40 }40 }
4141
42 fn realloc(allocator: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: u29) %[]u8 {42 fn realloc(allocator: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
43 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);43 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
44 if (new_size <= old_mem.len) {44 if (new_size <= old_mem.len) {
45 self.freed_bytes += old_mem.len - new_size;45 self.freed_bytes += old_mem.len - new_size;
std/debug/index.zig+52-52
...@@ -10,26 +10,17 @@ const builtin = @import("builtin");...@@ -10,26 +10,17 @@ const builtin = @import("builtin");
1010
11pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;11pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;
1212
13error MissingDebugInfo;
14error InvalidDebugInfo;
15error UnsupportedDebugInfo;
16error UnknownObjectFormat;
17error TodoSupportCoffDebugInfo;
18error TodoSupportMachoDebugInfo;
19error TodoSupportCOFFDebugInfo;
20
21
22/// Tries to write to stderr, unbuffered, and ignores any error returned.13/// Tries to write to stderr, unbuffered, and ignores any error returned.
23/// Does not append a newline.14/// Does not append a newline.
24/// TODO atomic/multithread support15/// TODO atomic/multithread support
25var stderr_file: io.File = undefined;16var stderr_file: io.File = undefined;
26var stderr_file_out_stream: io.FileOutStream = undefined;17var stderr_file_out_stream: io.FileOutStream = undefined;
27var stderr_stream: ?&io.OutStream = null;18var stderr_stream: ?&io.OutStream(io.FileOutStream.Error) = null;
28pub fn warn(comptime fmt: []const u8, args: ...) void {19pub fn warn(comptime fmt: []const u8, args: ...) void {
29 const stderr = getStderrStream() catch return;20 const stderr = getStderrStream() catch return;
30 stderr.print(fmt, args) catch return;21 stderr.print(fmt, args) catch return;
31}22}
32fn getStderrStream() %&io.OutStream {23fn getStderrStream() !&io.OutStream(io.FileOutStream.Error) {
33 if (stderr_stream) |st| {24 if (stderr_stream) |st| {
34 return st;25 return st;
35 } else {26 } else {
...@@ -42,7 +33,7 @@ fn getStderrStream() %&io.OutStream {...@@ -42,7 +33,7 @@ fn getStderrStream() %&io.OutStream {
42}33}
4334
44var self_debug_info: ?&ElfStackTrace = null;35var self_debug_info: ?&ElfStackTrace = null;
45pub fn getSelfDebugInfo() %&ElfStackTrace {36pub fn getSelfDebugInfo() !&ElfStackTrace {
46 if (self_debug_info) |info| {37 if (self_debug_info) |info| {
47 return info;38 return info;
48 } else {39 } else {
...@@ -149,11 +140,8 @@ const WHITE = "\x1b[37;1m";...@@ -149,11 +140,8 @@ const WHITE = "\x1b[37;1m";
149const DIM = "\x1b[2m";140const DIM = "\x1b[2m";
150const RESET = "\x1b[0m";141const RESET = "\x1b[0m";
151142
152error PathNotFound;143pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var, allocator: &mem.Allocator,
153error InvalidDebugInfo;144 debug_info: &ElfStackTrace, tty_color: bool) !void
154
155pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator,
156 debug_info: &ElfStackTrace, tty_color: bool) %void
157{145{
158 var frame_index: usize = undefined;146 var frame_index: usize = undefined;
159 var frames_left: usize = undefined;147 var frames_left: usize = undefined;
...@@ -174,8 +162,8 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.O...@@ -174,8 +162,8 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.O
174 }162 }
175}163}
176164
177pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator,165pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,
178 debug_info: &ElfStackTrace, tty_color: bool, ignore_frame_count: usize) %void166 debug_info: &ElfStackTrace, tty_color: bool, ignore_frame_count: usize) !void
179{167{
180 var ignored_count: usize = 0;168 var ignored_count: usize = 0;
181169
...@@ -191,7 +179,7 @@ pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocat...@@ -191,7 +179,7 @@ pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocat
191 }179 }
192}180}
193181
194fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, address: usize) %void {182fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: var, address: usize) !void {
195 if (builtin.os == builtin.Os.windows) {183 if (builtin.os == builtin.Os.windows) {
196 return error.UnsupportedDebugInfo;184 return error.UnsupportedDebugInfo;
197 }185 }
...@@ -221,7 +209,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a...@@ -221,7 +209,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a
221 try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");209 try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
222 }210 }
223 } else |err| switch (err) {211 } else |err| switch (err) {
224 error.EndOfFile, error.PathNotFound => {},212 error.EndOfFile => {},
225 else => return err,213 else => return err,
226 }214 }
227 } else |err| switch (err) {215 } else |err| switch (err) {
...@@ -232,7 +220,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a...@@ -232,7 +220,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a
232 }220 }
233}221}
234222
235pub fn openSelfDebugInfo(allocator: &mem.Allocator) %&ElfStackTrace {223pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {
236 switch (builtin.object_format) {224 switch (builtin.object_format) {
237 builtin.ObjectFormat.elf => {225 builtin.ObjectFormat.elf => {
238 const st = try allocator.create(ElfStackTrace);226 const st = try allocator.create(ElfStackTrace);
...@@ -276,7 +264,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) %&ElfStackTrace {...@@ -276,7 +264,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) %&ElfStackTrace {
276 }264 }
277}265}
278266
279fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_info: &const LineInfo) %void {267fn printLineFromFile(allocator: &mem.Allocator, out_stream: var, line_info: &const LineInfo) !void {
280 var f = try io.File.openRead(line_info.file_name, allocator);268 var f = try io.File.openRead(line_info.file_name, allocator);
281 defer f.close();269 defer f.close();
282 // TODO fstat and make sure that the file has the correct size270 // TODO fstat and make sure that the file has the correct size
...@@ -324,7 +312,7 @@ pub const ElfStackTrace = struct {...@@ -324,7 +312,7 @@ pub const ElfStackTrace = struct {
324 return self.abbrev_table_list.allocator;312 return self.abbrev_table_list.allocator;
325 }313 }
326314
327 pub fn readString(self: &ElfStackTrace) %[]u8 {315 pub fn readString(self: &ElfStackTrace) ![]u8 {
328 var in_file_stream = io.FileInStream.init(&self.self_exe_file);316 var in_file_stream = io.FileInStream.init(&self.self_exe_file);
329 const in_stream = &in_file_stream.stream;317 const in_stream = &in_file_stream.stream;
330 return readStringRaw(self.allocator(), in_stream);318 return readStringRaw(self.allocator(), in_stream);
...@@ -387,7 +375,7 @@ const Constant = struct {...@@ -387,7 +375,7 @@ const Constant = struct {
387 payload: []u8,375 payload: []u8,
388 signed: bool,376 signed: bool,
389377
390 fn asUnsignedLe(self: &const Constant) %u64 {378 fn asUnsignedLe(self: &const Constant) !u64 {
391 if (self.payload.len > @sizeOf(u64))379 if (self.payload.len > @sizeOf(u64))
392 return error.InvalidDebugInfo;380 return error.InvalidDebugInfo;
393 if (self.signed)381 if (self.signed)
...@@ -414,7 +402,7 @@ const Die = struct {...@@ -414,7 +402,7 @@ const Die = struct {
414 return null;402 return null;
415 }403 }
416404
417 fn getAttrAddr(self: &const Die, id: u64) %u64 {405 fn getAttrAddr(self: &const Die, id: u64) !u64 {
418 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;406 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
419 return switch (*form_value) {407 return switch (*form_value) {
420 FormValue.Address => |value| value,408 FormValue.Address => |value| value,
...@@ -422,7 +410,7 @@ const Die = struct {...@@ -422,7 +410,7 @@ const Die = struct {
422 };410 };
423 }411 }
424412
425 fn getAttrSecOffset(self: &const Die, id: u64) %u64 {413 fn getAttrSecOffset(self: &const Die, id: u64) !u64 {
426 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;414 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
427 return switch (*form_value) {415 return switch (*form_value) {
428 FormValue.Const => |value| value.asUnsignedLe(),416 FormValue.Const => |value| value.asUnsignedLe(),
...@@ -431,7 +419,7 @@ const Die = struct {...@@ -431,7 +419,7 @@ const Die = struct {
431 };419 };
432 }420 }
433421
434 fn getAttrUnsignedLe(self: &const Die, id: u64) %u64 {422 fn getAttrUnsignedLe(self: &const Die, id: u64) !u64 {
435 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;423 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
436 return switch (*form_value) {424 return switch (*form_value) {
437 FormValue.Const => |value| value.asUnsignedLe(),425 FormValue.Const => |value| value.asUnsignedLe(),
...@@ -439,7 +427,7 @@ const Die = struct {...@@ -439,7 +427,7 @@ const Die = struct {
439 };427 };
440 }428 }
441429
442 fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) %[]u8 {430 fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) ![]u8 {
443 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;431 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
444 return switch (*form_value) {432 return switch (*form_value) {
445 FormValue.String => |value| value,433 FormValue.String => |value| value,
...@@ -512,7 +500,7 @@ const LineNumberProgram = struct {...@@ -512,7 +500,7 @@ const LineNumberProgram = struct {
512 };500 };
513 }501 }
514502
515 pub fn checkLineMatch(self: &LineNumberProgram) %?LineInfo {503 pub fn checkLineMatch(self: &LineNumberProgram) !?LineInfo {
516 if (self.target_address >= self.prev_address and self.target_address < self.address) {504 if (self.target_address >= self.prev_address and self.target_address < self.address) {
517 const file_entry = if (self.prev_file == 0) {505 const file_entry = if (self.prev_file == 0) {
518 return error.MissingDebugInfo;506 return error.MissingDebugInfo;
...@@ -544,7 +532,7 @@ const LineNumberProgram = struct {...@@ -544,7 +532,7 @@ const LineNumberProgram = struct {
544 }532 }
545};533};
546534
547fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) %[]u8 {535fn readStringRaw(allocator: &mem.Allocator, in_stream: var) ![]u8 {
548 var buf = ArrayList(u8).init(allocator);536 var buf = ArrayList(u8).init(allocator);
549 while (true) {537 while (true) {
550 const byte = try in_stream.readByte();538 const byte = try in_stream.readByte();
...@@ -555,58 +543,70 @@ fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) %[]u8 {...@@ -555,58 +543,70 @@ fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) %[]u8 {
555 return buf.toSlice();543 return buf.toSlice();
556}544}
557545
558fn getString(st: &ElfStackTrace, offset: u64) %[]u8 {546fn getString(st: &ElfStackTrace, offset: u64) ![]u8 {
559 const pos = st.debug_str.offset + offset;547 const pos = st.debug_str.offset + offset;
560 try st.self_exe_file.seekTo(pos);548 try st.self_exe_file.seekTo(pos);
561 return st.readString();549 return st.readString();
562}550}
563551
564fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) %[]u8 {552fn readAllocBytes(allocator: &mem.Allocator, in_stream: var, size: usize) ![]u8 {
565 const buf = try global_allocator.alloc(u8, size);553 const buf = try global_allocator.alloc(u8, size);
566 errdefer global_allocator.free(buf);554 errdefer global_allocator.free(buf);
567 if ((try in_stream.read(buf)) < size) return error.EndOfFile;555 if ((try in_stream.read(buf)) < size) return error.EndOfFile;
568 return buf;556 return buf;
569}557}
570558
571fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) %FormValue {559fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
572 const buf = try readAllocBytes(allocator, in_stream, size);560 const buf = try readAllocBytes(allocator, in_stream, size);
573 return FormValue { .Block = buf };561 return FormValue { .Block = buf };
574}562}
575563
576fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) %FormValue {564fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
577 const block_len = try in_stream.readVarInt(builtin.Endian.Little, usize, size);565 const block_len = try in_stream.readVarInt(builtin.Endian.Little, usize, size);
578 return parseFormValueBlockLen(allocator, in_stream, block_len);566 return parseFormValueBlockLen(allocator, in_stream, block_len);
579}567}
580568
581fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) %FormValue {569fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue {
582 return FormValue { .Const = Constant {570 return FormValue { .Const = Constant {
583 .signed = signed,571 .signed = signed,
584 .payload = try readAllocBytes(allocator, in_stream, size),572 .payload = try readAllocBytes(allocator, in_stream, size),
585 }};573 }};
586}574}
587575
588fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) %u64 {576fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
589 return if (is_64) try in_stream.readIntLe(u64)577 return if (is_64) try in_stream.readIntLe(u64)
590 else u64(try in_stream.readIntLe(u32)) ;578 else u64(try in_stream.readIntLe(u32)) ;
591}579}
592580
593fn parseFormValueTargetAddrSize(in_stream: &io.InStream) %u64 {581fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
594 return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32))582 return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32))
595 else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64)583 else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64)
596 else unreachable;584 else unreachable;
597}585}
598586
599fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) %FormValue {587fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
600 const buf = try readAllocBytes(allocator, in_stream, size);588 const buf = try readAllocBytes(allocator, in_stream, size);
601 return FormValue { .Ref = buf };589 return FormValue { .Ref = buf };
602}590}
603591
604fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptime T: type) %FormValue {592fn parseFormValueRef(allocator: &mem.Allocator, in_stream: var, comptime T: type) !FormValue {
605 const block_len = try in_stream.readIntLe(T);593 const block_len = try in_stream.readIntLe(T);
606 return parseFormValueRefLen(allocator, in_stream, block_len);594 return parseFormValueRefLen(allocator, in_stream, block_len);
607}595}
608596
609fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool) %FormValue {597const ParseFormValueError = error {
598 EndOfStream,
599 Io,
600 BadFd,
601 Unexpected,
602 InvalidDebugInfo,
603 EndOfFile,
604 OutOfMemory,
605};
606
607fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64: bool)
608 ParseFormValueError!FormValue
609{
610 return switch (form_id) {610 return switch (form_id) {
611 DW.FORM_addr => FormValue { .Address = try parseFormValueTargetAddrSize(in_stream) },611 DW.FORM_addr => FormValue { .Address = try parseFormValueTargetAddrSize(in_stream) },
612 DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),612 DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
...@@ -656,7 +656,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u...@@ -656,7 +656,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
656 };656 };
657}657}
658658
659fn parseAbbrevTable(st: &ElfStackTrace) %AbbrevTable {659fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable {
660 const in_file = &st.self_exe_file;660 const in_file = &st.self_exe_file;
661 var in_file_stream = io.FileInStream.init(in_file);661 var in_file_stream = io.FileInStream.init(in_file);
662 const in_stream = &in_file_stream.stream;662 const in_stream = &in_file_stream.stream;
...@@ -688,7 +688,7 @@ fn parseAbbrevTable(st: &ElfStackTrace) %AbbrevTable {...@@ -688,7 +688,7 @@ fn parseAbbrevTable(st: &ElfStackTrace) %AbbrevTable {
688688
689/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,689/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
690/// seeks in the stream and parses it.690/// seeks in the stream and parses it.
691fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) %&const AbbrevTable {691fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) !&const AbbrevTable {
692 for (st.abbrev_table_list.toSlice()) |*header| {692 for (st.abbrev_table_list.toSlice()) |*header| {
693 if (header.offset == abbrev_offset) {693 if (header.offset == abbrev_offset) {
694 return &header.table;694 return &header.table;
...@@ -710,7 +710,7 @@ fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) ?&con...@@ -710,7 +710,7 @@ fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) ?&con
710 return null;710 return null;
711}711}
712712
713fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) %Die {713fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) !Die {
714 const in_file = &st.self_exe_file;714 const in_file = &st.self_exe_file;
715 var in_file_stream = io.FileInStream.init(in_file);715 var in_file_stream = io.FileInStream.init(in_file);
716 const in_stream = &in_file_stream.stream;716 const in_stream = &in_file_stream.stream;
...@@ -732,7 +732,7 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) %...@@ -732,7 +732,7 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) %
732 return result;732 return result;
733}733}
734734
735fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, target_address: usize) %LineInfo {735fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, target_address: usize) !LineInfo {
736 const compile_unit_cwd = try compile_unit.die.getAttrString(st, DW.AT_comp_dir);736 const compile_unit_cwd = try compile_unit.die.getAttrString(st, DW.AT_comp_dir);
737737
738 const in_file = &st.self_exe_file;738 const in_file = &st.self_exe_file;
...@@ -747,7 +747,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe...@@ -747,7 +747,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
747 try in_file.seekTo(this_offset);747 try in_file.seekTo(this_offset);
748748
749 var is_64: bool = undefined;749 var is_64: bool = undefined;
750 const unit_length = try readInitialLength(in_stream, &is_64);750 const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
751 if (unit_length == 0)751 if (unit_length == 0)
752 return error.MissingDebugInfo;752 return error.MissingDebugInfo;
753 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));753 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
...@@ -910,7 +910,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe...@@ -910,7 +910,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
910 return error.MissingDebugInfo;910 return error.MissingDebugInfo;
911}911}
912912
913fn scanAllCompileUnits(st: &ElfStackTrace) %void {913fn scanAllCompileUnits(st: &ElfStackTrace) !void {
914 const debug_info_end = st.debug_info.offset + st.debug_info.size;914 const debug_info_end = st.debug_info.offset + st.debug_info.size;
915 var this_unit_offset = st.debug_info.offset;915 var this_unit_offset = st.debug_info.offset;
916 var cu_index: usize = 0;916 var cu_index: usize = 0;
...@@ -922,7 +922,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) %void {...@@ -922,7 +922,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) %void {
922 try st.self_exe_file.seekTo(this_unit_offset);922 try st.self_exe_file.seekTo(this_unit_offset);
923923
924 var is_64: bool = undefined;924 var is_64: bool = undefined;
925 const unit_length = try readInitialLength(in_stream, &is_64);925 const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
926 if (unit_length == 0)926 if (unit_length == 0)
927 return;927 return;
928 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));928 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
...@@ -986,7 +986,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) %void {...@@ -986,7 +986,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) %void {
986 }986 }
987}987}
988988
989fn findCompileUnit(st: &ElfStackTrace, target_address: u64) %&const CompileUnit {989fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit {
990 var in_file_stream = io.FileInStream.init(&st.self_exe_file);990 var in_file_stream = io.FileInStream.init(&st.self_exe_file);
991 const in_stream = &in_file_stream.stream;991 const in_stream = &in_file_stream.stream;
992 for (st.compile_unit_list.toSlice()) |*compile_unit| {992 for (st.compile_unit_list.toSlice()) |*compile_unit| {
...@@ -1022,7 +1022,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) %&const CompileUnit...@@ -1022,7 +1022,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) %&const CompileUnit
1022 return error.MissingDebugInfo;1022 return error.MissingDebugInfo;
1023}1023}
10241024
1025fn readInitialLength(in_stream: &io.InStream, is_64: &bool) %u64 {1025fn readInitialLength(comptime E: type, in_stream: &io.InStream(E), is_64: &bool) !u64 {
1026 const first_32_bits = try in_stream.readIntLe(u32);1026 const first_32_bits = try in_stream.readIntLe(u32);
1027 *is_64 = (first_32_bits == 0xffffffff);1027 *is_64 = (first_32_bits == 0xffffffff);
1028 if (*is_64) {1028 if (*is_64) {
...@@ -1033,7 +1033,7 @@ fn readInitialLength(in_stream: &io.InStream, is_64: &bool) %u64 {...@@ -1033,7 +1033,7 @@ fn readInitialLength(in_stream: &io.InStream, is_64: &bool) %u64 {
1033 }1033 }
1034}1034}
10351035
1036fn readULeb128(in_stream: &io.InStream) %u64 {1036fn readULeb128(in_stream: var) !u64 {
1037 var result: u64 = 0;1037 var result: u64 = 0;
1038 var shift: usize = 0;1038 var shift: usize = 0;
10391039
...@@ -1054,7 +1054,7 @@ fn readULeb128(in_stream: &io.InStream) %u64 {...@@ -1054,7 +1054,7 @@ fn readULeb128(in_stream: &io.InStream) %u64 {
1054 }1054 }
1055}1055}
10561056
1057fn readILeb128(in_stream: &io.InStream) %i64 {1057fn readILeb128(in_stream: var) !i64 {
1058 var result: i64 = 0;1058 var result: i64 = 0;
1059 var shift: usize = 0;1059 var shift: usize = 0;
10601060
std/elf.zig+4-6
...@@ -6,8 +6,6 @@ const mem = std.mem;...@@ -6,8 +6,6 @@ const mem = std.mem;
6const debug = std.debug;6const debug = std.debug;
7const InStream = std.stream.InStream;7const InStream = std.stream.InStream;
88
9error InvalidFormat;
10
11pub const SHT_NULL = 0;9pub const SHT_NULL = 0;
12pub const SHT_PROGBITS = 1;10pub const SHT_PROGBITS = 1;
13pub const SHT_SYMTAB = 2;11pub const SHT_SYMTAB = 2;
...@@ -81,14 +79,14 @@ pub const Elf = struct {...@@ -81,14 +79,14 @@ pub const Elf = struct {
81 prealloc_file: io.File,79 prealloc_file: io.File,
8280
83 /// Call close when done.81 /// Call close when done.
84 pub fn openPath(elf: &Elf, allocator: &mem.Allocator, path: []const u8) %void {82 pub fn openPath(elf: &Elf, allocator: &mem.Allocator, path: []const u8) !void {
85 try elf.prealloc_file.open(path);83 try elf.prealloc_file.open(path);
86 try elf.openFile(allocator, &elf.prealloc_file);84 try elf.openFile(allocator, &elf.prealloc_file);
87 elf.auto_close_stream = true;85 elf.auto_close_stream = true;
88 }86 }
8987
90 /// Call close when done.88 /// Call close when done.
91 pub fn openFile(elf: &Elf, allocator: &mem.Allocator, file: &io.File) %void {89 pub fn openFile(elf: &Elf, allocator: &mem.Allocator, file: &io.File) !void {
92 elf.allocator = allocator;90 elf.allocator = allocator;
93 elf.in_file = file;91 elf.in_file = file;
94 elf.auto_close_stream = false;92 elf.auto_close_stream = false;
...@@ -239,7 +237,7 @@ pub const Elf = struct {...@@ -239,7 +237,7 @@ pub const Elf = struct {
239 elf.in_file.close();237 elf.in_file.close();
240 }238 }
241239
242 pub fn findSection(elf: &Elf, name: []const u8) %?&SectionHeader {240 pub fn findSection(elf: &Elf, name: []const u8) !?&SectionHeader {
243 var file_stream = io.FileInStream.init(elf.in_file);241 var file_stream = io.FileInStream.init(elf.in_file);
244 const in = &file_stream.stream;242 const in = &file_stream.stream;
245243
...@@ -263,7 +261,7 @@ pub const Elf = struct {...@@ -263,7 +261,7 @@ pub const Elf = struct {
263 return null;261 return null;
264 }262 }
265263
266 pub fn seekToSection(elf: &Elf, elf_section: &SectionHeader) %void {264 pub fn seekToSection(elf: &Elf, elf_section: &SectionHeader) !void {
267 try elf.in_file.seekTo(elf_section.offset);265 try elf.in_file.seekTo(elf_section.offset);
268 }266 }
269};267};
std/fmt/index.zig+56-52
...@@ -24,8 +24,8 @@ const State = enum { // TODO put inside format function and make sure the name a...@@ -24,8 +24,8 @@ const State = enum { // TODO put inside format function and make sure the name a
24/// Renders fmt string with args, calling output with slices of bytes.24/// Renders fmt string with args, calling output with slices of bytes.
25/// If `output` returns an error, the error is returned from `format` and25/// If `output` returns an error, the error is returned from `format` and
26/// `output` is not called again.26/// `output` is not called again.
27pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,27pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void,
28 comptime fmt: []const u8, args: ...) %void28 comptime fmt: []const u8, args: ...) Errors!void
29{29{
30 comptime var start_index = 0;30 comptime var start_index = 0;
31 comptime var state = State.Start;31 comptime var state = State.Start;
...@@ -58,7 +58,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,...@@ -58,7 +58,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
58 start_index = i;58 start_index = i;
59 },59 },
60 '}' => {60 '}' => {
61 try formatValue(args[next_arg], context, output);61 try formatValue(args[next_arg], context, Errors, output);
62 next_arg += 1;62 next_arg += 1;
63 state = State.Start;63 state = State.Start;
64 start_index = i + 1;64 start_index = i + 1;
...@@ -110,7 +110,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,...@@ -110,7 +110,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
110 },110 },
111 State.Integer => switch (c) {111 State.Integer => switch (c) {
112 '}' => {112 '}' => {
113 try formatInt(args[next_arg], radix, uppercase, width, context, output);113 try formatInt(args[next_arg], radix, uppercase, width, context, Errors, output);
114 next_arg += 1;114 next_arg += 1;
115 state = State.Start;115 state = State.Start;
116 start_index = i + 1;116 start_index = i + 1;
...@@ -124,7 +124,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,...@@ -124,7 +124,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
124 State.IntegerWidth => switch (c) {124 State.IntegerWidth => switch (c) {
125 '}' => {125 '}' => {
126 width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);126 width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);
127 try formatInt(args[next_arg], radix, uppercase, width, context, output);127 try formatInt(args[next_arg], radix, uppercase, width, context, Errors, output);
128 next_arg += 1;128 next_arg += 1;
129 state = State.Start;129 state = State.Start;
130 start_index = i + 1;130 start_index = i + 1;
...@@ -134,7 +134,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,...@@ -134,7 +134,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
134 },134 },
135 State.Float => switch (c) {135 State.Float => switch (c) {
136 '}' => {136 '}' => {
137 try formatFloatDecimal(args[next_arg], 0, context, output);137 try formatFloatDecimal(args[next_arg], 0, context, Errors, output);
138 next_arg += 1;138 next_arg += 1;
139 state = State.Start;139 state = State.Start;
140 start_index = i + 1;140 start_index = i + 1;
...@@ -148,7 +148,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,...@@ -148,7 +148,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
148 State.FloatWidth => switch (c) {148 State.FloatWidth => switch (c) {
149 '}' => {149 '}' => {
150 width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);150 width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);
151 try formatFloatDecimal(args[next_arg], width, context, output);151 try formatFloatDecimal(args[next_arg], width, context, Errors, output);
152 next_arg += 1;152 next_arg += 1;
153 state = State.Start;153 state = State.Start;
154 start_index = i + 1;154 start_index = i + 1;
...@@ -159,7 +159,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,...@@ -159,7 +159,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
159 State.BufWidth => switch (c) {159 State.BufWidth => switch (c) {
160 '}' => {160 '}' => {
161 width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);161 width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);
162 try formatBuf(args[next_arg], width, context, output);162 try formatBuf(args[next_arg], width, context, Errors, output);
163 next_arg += 1;163 next_arg += 1;
164 state = State.Start;164 state = State.Start;
165 start_index = i + 1;165 start_index = i + 1;
...@@ -169,7 +169,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,...@@ -169,7 +169,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
169 },169 },
170 State.Character => switch (c) {170 State.Character => switch (c) {
171 '}' => {171 '}' => {
172 try formatAsciiChar(args[next_arg], context, output);172 try formatAsciiChar(args[next_arg], context, Errors, output);
173 next_arg += 1;173 next_arg += 1;
174 state = State.Start;174 state = State.Start;
175 start_index = i + 1;175 start_index = i + 1;
...@@ -191,14 +191,14 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,...@@ -191,14 +191,14 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
191 }191 }
192}192}
193193
194pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []const u8)%void) %void {194pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {
195 const T = @typeOf(value);195 const T = @typeOf(value);
196 switch (@typeId(T)) {196 switch (@typeId(T)) {
197 builtin.TypeId.Int => {197 builtin.TypeId.Int => {
198 return formatInt(value, 10, false, 0, context, output);198 return formatInt(value, 10, false, 0, context, Errors, output);
199 },199 },
200 builtin.TypeId.Float => {200 builtin.TypeId.Float => {
201 return formatFloat(value, context, output);201 return formatFloat(value, context, Errors, output);
202 },202 },
203 builtin.TypeId.Void => {203 builtin.TypeId.Void => {
204 return output(context, "void");204 return output(context, "void");
...@@ -208,19 +208,19 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons...@@ -208,19 +208,19 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons
208 },208 },
209 builtin.TypeId.Nullable => {209 builtin.TypeId.Nullable => {
210 if (value) |payload| {210 if (value) |payload| {
211 return formatValue(payload, context, output);211 return formatValue(payload, context, Errors, output);
212 } else {212 } else {
213 return output(context, "null");213 return output(context, "null");
214 }214 }
215 },215 },
216 builtin.TypeId.ErrorUnion => {216 builtin.TypeId.ErrorUnion => {
217 if (value) |payload| {217 if (value) |payload| {
218 return formatValue(payload, context, output);218 return formatValue(payload, context, Errors, output);
219 } else |err| {219 } else |err| {
220 return formatValue(err, context, output);220 return formatValue(err, context, Errors, output);
221 }221 }
222 },222 },
223 builtin.TypeId.Error => {223 builtin.TypeId.ErrorSet => {
224 try output(context, "error.");224 try output(context, "error.");
225 return output(context, @errorName(value));225 return output(context, @errorName(value));
226 },226 },
...@@ -228,7 +228,7 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons...@@ -228,7 +228,7 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons
228 if (@typeId(T.Child) == builtin.TypeId.Array and T.Child.Child == u8) {228 if (@typeId(T.Child) == builtin.TypeId.Array and T.Child.Child == u8) {
229 return output(context, (*value)[0..]);229 return output(context, (*value)[0..]);
230 } else {230 } else {
231 return format(context, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));231 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
232 }232 }
233 },233 },
234 else => if (@canImplicitCast([]const u8, value)) {234 else => if (@canImplicitCast([]const u8, value)) {
...@@ -240,12 +240,12 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons...@@ -240,12 +240,12 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons
240 }240 }
241}241}
242242
243pub fn formatAsciiChar(c: u8, context: var, output: fn(@typeOf(context), []const u8)%void) %void {243pub fn formatAsciiChar(c: u8, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {
244 return output(context, (&c)[0..1]);244 return output(context, (&c)[0..1]);
245}245}
246246
247pub fn formatBuf(buf: []const u8, width: usize,247pub fn formatBuf(buf: []const u8, width: usize,
248 context: var, output: fn(@typeOf(context), []const u8)%void) %void248 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
249{249{
250 try output(context, buf);250 try output(context, buf);
251251
...@@ -256,7 +256,7 @@ pub fn formatBuf(buf: []const u8, width: usize,...@@ -256,7 +256,7 @@ pub fn formatBuf(buf: []const u8, width: usize,
256 }256 }
257}257}
258258
259pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []const u8)%void) %void {259pub fn formatFloat(value: var, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {
260 var x = f64(value);260 var x = f64(value);
261261
262 // Errol doesn't handle these special cases.262 // Errol doesn't handle these special cases.
...@@ -290,11 +290,11 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons...@@ -290,11 +290,11 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons
290290
291 if (float_decimal.exp != 1) {291 if (float_decimal.exp != 1) {
292 try output(context, "e");292 try output(context, "e");
293 try formatInt(float_decimal.exp - 1, 10, false, 0, context, output);293 try formatInt(float_decimal.exp - 1, 10, false, 0, context, Errors, output);
294 }294 }
295}295}
296296
297pub fn formatFloatDecimal(value: var, precision: usize, context: var, output: fn(@typeOf(context), []const u8)%void) %void {297pub fn formatFloatDecimal(value: var, precision: usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {
298 var x = f64(value);298 var x = f64(value);
299299
300 // Errol doesn't handle these special cases.300 // Errol doesn't handle these special cases.
...@@ -336,17 +336,17 @@ pub fn formatFloatDecimal(value: var, precision: usize, context: var, output: fn...@@ -336,17 +336,17 @@ pub fn formatFloatDecimal(value: var, precision: usize, context: var, output: fn
336336
337337
338pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,338pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,
339 context: var, output: fn(@typeOf(context), []const u8)%void) %void339 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
340{340{
341 if (@typeOf(value).is_signed) {341 if (@typeOf(value).is_signed) {
342 return formatIntSigned(value, base, uppercase, width, context, output);342 return formatIntSigned(value, base, uppercase, width, context, Errors, output);
343 } else {343 } else {
344 return formatIntUnsigned(value, base, uppercase, width, context, output);344 return formatIntUnsigned(value, base, uppercase, width, context, Errors, output);
345 }345 }
346}346}
347347
348fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,348fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,
349 context: var, output: fn(@typeOf(context), []const u8)%void) %void349 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
350{350{
351 const uint = @IntType(false, @typeOf(value).bit_count);351 const uint = @IntType(false, @typeOf(value).bit_count);
352 if (value < 0) {352 if (value < 0) {
...@@ -354,20 +354,20 @@ fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,...@@ -354,20 +354,20 @@ fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,
354 try output(context, (&minus_sign)[0..1]);354 try output(context, (&minus_sign)[0..1]);
355 const new_value = uint(-(value + 1)) + 1;355 const new_value = uint(-(value + 1)) + 1;
356 const new_width = if (width == 0) 0 else (width - 1);356 const new_width = if (width == 0) 0 else (width - 1);
357 return formatIntUnsigned(new_value, base, uppercase, new_width, context, output);357 return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
358 } else if (width == 0) {358 } else if (width == 0) {
359 return formatIntUnsigned(uint(value), base, uppercase, width, context, output);359 return formatIntUnsigned(uint(value), base, uppercase, width, context, Errors, output);
360 } else {360 } else {
361 const plus_sign: u8 = '+';361 const plus_sign: u8 = '+';
362 try output(context, (&plus_sign)[0..1]);362 try output(context, (&plus_sign)[0..1]);
363 const new_value = uint(value);363 const new_value = uint(value);
364 const new_width = if (width == 0) 0 else (width - 1);364 const new_width = if (width == 0) 0 else (width - 1);
365 return formatIntUnsigned(new_value, base, uppercase, new_width, context, output);365 return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
366 }366 }
367}367}
368368
369fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,369fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
370 context: var, output: fn(@typeOf(context), []const u8)%void) %void370 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
371{371{
372 // max_int_digits accounts for the minus sign. when printing an unsigned372 // max_int_digits accounts for the minus sign. when printing an unsigned
373 // number we don't need to do that.373 // number we don't need to do that.
...@@ -410,19 +410,19 @@ pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width:...@@ -410,19 +410,19 @@ pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width:
410 .out_buf = out_buf,410 .out_buf = out_buf,
411 .index = 0,411 .index = 0,
412 };412 };
413 formatInt(value, base, uppercase, width, &context, formatIntCallback) catch unreachable;413 formatInt(value, base, uppercase, width, &context, error{}, formatIntCallback) catch unreachable;
414 return context.index;414 return context.index;
415}415}
416const FormatIntBuf = struct {416const FormatIntBuf = struct {
417 out_buf: []u8,417 out_buf: []u8,
418 index: usize,418 index: usize,
419};419};
420fn formatIntCallback(context: &FormatIntBuf, bytes: []const u8) %void {420fn formatIntCallback(context: &FormatIntBuf, bytes: []const u8) (error{}!void) {
421 mem.copy(u8, context.out_buf[context.index..], bytes);421 mem.copy(u8, context.out_buf[context.index..], bytes);
422 context.index += bytes.len;422 context.index += bytes.len;
423}423}
424424
425pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) %T {425pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
426 if (!T.is_signed)426 if (!T.is_signed)
427 return parseUnsigned(T, buf, radix);427 return parseUnsigned(T, buf, radix);
428 if (buf.len == 0)428 if (buf.len == 0)
...@@ -439,14 +439,21 @@ pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) %T {...@@ -439,14 +439,21 @@ pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) %T {
439test "fmt.parseInt" {439test "fmt.parseInt" {
440 assert((parseInt(i32, "-10", 10) catch unreachable) == -10);440 assert((parseInt(i32, "-10", 10) catch unreachable) == -10);
441 assert((parseInt(i32, "+10", 10) catch unreachable) == 10);441 assert((parseInt(i32, "+10", 10) catch unreachable) == 10);
442 assert(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidChar);442 assert(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter);
443 assert(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidChar);443 assert(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter);
444 assert(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidChar);444 assert(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter);
445 assert((parseInt(u8, "255", 10) catch unreachable) == 255);445 assert((parseInt(u8, "255", 10) catch unreachable) == 255);
446 assert(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);446 assert(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
447}447}
448448
449pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) %T {449const ParseUnsignedError = error {
450 /// The result cannot fit in the type specified
451 Overflow,
452 /// The input had a byte that was not a digit
453 InvalidCharacter,
454};
455
456pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsignedError!T {
450 var x: T = 0;457 var x: T = 0;
451458
452 for (buf) |c| {459 for (buf) |c| {
...@@ -458,17 +465,16 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) %T {...@@ -458,17 +465,16 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) %T {
458 return x;465 return x;
459}466}
460467
461error InvalidChar;468fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
462fn charToDigit(c: u8, radix: u8) %u8 {
463 const value = switch (c) {469 const value = switch (c) {
464 '0' ... '9' => c - '0',470 '0' ... '9' => c - '0',
465 'A' ... 'Z' => c - 'A' + 10,471 'A' ... 'Z' => c - 'A' + 10,
466 'a' ... 'z' => c - 'a' + 10,472 'a' ... 'z' => c - 'a' + 10,
467 else => return error.InvalidChar,473 else => return error.InvalidCharacter,
468 };474 };
469475
470 if (value >= radix)476 if (value >= radix)
471 return error.InvalidChar;477 return error.InvalidCharacter;
472478
473 return value;479 return value;
474}480}
...@@ -485,28 +491,26 @@ const BufPrintContext = struct {...@@ -485,28 +491,26 @@ const BufPrintContext = struct {
485 remaining: []u8,491 remaining: []u8,
486};492};
487493
488error BufferTooSmall;494fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) !void {
489fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) %void {
490 if (context.remaining.len < bytes.len) return error.BufferTooSmall;495 if (context.remaining.len < bytes.len) return error.BufferTooSmall;
491 mem.copy(u8, context.remaining, bytes);496 mem.copy(u8, context.remaining, bytes);
492 context.remaining = context.remaining[bytes.len..];497 context.remaining = context.remaining[bytes.len..];
493}498}
494499
495pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) %[]u8 {500pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {
496 var context = BufPrintContext { .remaining = buf, };501 var context = BufPrintContext { .remaining = buf, };
497 try format(&context, bufPrintWrite, fmt, args);502 try format(&context, error{BufferTooSmall}, bufPrintWrite, fmt, args);
498 return buf[0..buf.len - context.remaining.len];503 return buf[0..buf.len - context.remaining.len];
499}504}
500505
501pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...) %[]u8 {506pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...) ![]u8 {
502 var size: usize = 0;507 var size: usize = 0;
503 // Cannot fail because `countSize` cannot fail.508 format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
504 format(&size, countSize, fmt, args) catch unreachable;
505 const buf = try allocator.alloc(u8, size);509 const buf = try allocator.alloc(u8, size);
506 return bufPrint(buf, fmt, args);510 return bufPrint(buf, fmt, args);
507}511}
508512
509fn countSize(size: &usize, bytes: []const u8) %void {513fn countSize(size: &usize, bytes: []const u8) (error{}!void) {
510 *size += bytes.len;514 *size += bytes.len;
511}515}
512516
...@@ -534,7 +538,7 @@ fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, width: u...@@ -534,7 +538,7 @@ fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, width: u
534538
535test "parse u64 digit too big" {539test "parse u64 digit too big" {
536 _ = parseUnsigned(u64, "123a", 10) catch |err| {540 _ = parseUnsigned(u64, "123a", 10) catch |err| {
537 if (err == error.InvalidChar) return;541 if (err == error.InvalidCharacter) return;
538 unreachable;542 unreachable;
539 };543 };
540 unreachable;544 unreachable;
...@@ -567,13 +571,13 @@ test "fmt.format" {...@@ -567,13 +571,13 @@ test "fmt.format" {
567 }571 }
568 {572 {
569 var buf1: [32]u8 = undefined;573 var buf1: [32]u8 = undefined;
570 const value: %i32 = 1234;574 const value: error!i32 = 1234;
571 const result = try bufPrint(buf1[0..], "error union: {}\n", value);575 const result = try bufPrint(buf1[0..], "error union: {}\n", value);
572 assert(mem.eql(u8, result, "error union: 1234\n"));576 assert(mem.eql(u8, result, "error union: 1234\n"));
573 }577 }
574 {578 {
575 var buf1: [32]u8 = undefined;579 var buf1: [32]u8 = undefined;
576 const value: %i32 = error.InvalidChar;580 const value: error!i32 = error.InvalidChar;
577 const result = try bufPrint(buf1[0..], "error union: {}\n", value);581 const result = try bufPrint(buf1[0..], "error union: {}\n", value);
578 assert(mem.eql(u8, result, "error union: error.InvalidChar\n"));582 assert(mem.eql(u8, result, "error union: error.InvalidChar\n"));
579 }583 }
std/hash_map.zig+2-2
...@@ -80,7 +80,7 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -80,7 +80,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
80 }80 }
8181
82 /// Returns the value that was already there.82 /// Returns the value that was already there.
83 pub fn put(hm: &Self, key: K, value: &const V) %?V {83 pub fn put(hm: &Self, key: K, value: &const V) !?V {
84 if (hm.entries.len == 0) {84 if (hm.entries.len == 0) {
85 try hm.initCapacity(16);85 try hm.initCapacity(16);
86 }86 }
...@@ -151,7 +151,7 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -151,7 +151,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
151 };151 };
152 }152 }
153153
154 fn initCapacity(hm: &Self, capacity: usize) %void {154 fn initCapacity(hm: &Self, capacity: usize) !void {
155 hm.entries = try hm.allocator.alloc(Entry, capacity);155 hm.entries = try hm.allocator.alloc(Entry, capacity);
156 hm.size = 0;156 hm.size = 0;
157 hm.max_distance_from_start_index = 0;157 hm.max_distance_from_start_index = 0;
std/heap.zig+5-7
...@@ -9,8 +9,6 @@ const c = std.c;...@@ -9,8 +9,6 @@ const c = std.c;
99
10const Allocator = mem.Allocator;10const Allocator = mem.Allocator;
1111
12error OutOfMemory;
13
14pub const c_allocator = &c_allocator_state;12pub const c_allocator = &c_allocator_state;
15var c_allocator_state = Allocator {13var c_allocator_state = Allocator {
16 .allocFn = cAlloc,14 .allocFn = cAlloc,
...@@ -18,14 +16,14 @@ var c_allocator_state = Allocator {...@@ -18,14 +16,14 @@ var c_allocator_state = Allocator {
18 .freeFn = cFree,16 .freeFn = cFree,
19};17};
2018
21fn cAlloc(self: &Allocator, n: usize, alignment: u29) %[]u8 {19fn cAlloc(self: &Allocator, n: usize, alignment: u29) ![]u8 {
22 return if (c.malloc(usize(n))) |buf|20 return if (c.malloc(usize(n))) |buf|
23 @ptrCast(&u8, buf)[0..n]21 @ptrCast(&u8, buf)[0..n]
24 else22 else
25 error.OutOfMemory;23 error.OutOfMemory;
26}24}
2725
28fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) %[]u8 {26fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
29 const old_ptr = @ptrCast(&c_void, old_mem.ptr);27 const old_ptr = @ptrCast(&c_void, old_mem.ptr);
30 if (c.realloc(old_ptr, new_size)) |buf| {28 if (c.realloc(old_ptr, new_size)) |buf| {
31 return @ptrCast(&u8, buf)[0..new_size];29 return @ptrCast(&u8, buf)[0..new_size];
...@@ -47,7 +45,7 @@ pub const IncrementingAllocator = struct {...@@ -47,7 +45,7 @@ pub const IncrementingAllocator = struct {
47 end_index: usize,45 end_index: usize,
48 heap_handle: if (builtin.os == Os.windows) os.windows.HANDLE else void,46 heap_handle: if (builtin.os == Os.windows) os.windows.HANDLE else void,
4947
50 fn init(capacity: usize) %IncrementingAllocator {48 fn init(capacity: usize) !IncrementingAllocator {
51 switch (builtin.os) {49 switch (builtin.os) {
52 Os.linux, Os.macosx, Os.ios => {50 Os.linux, Os.macosx, Os.ios => {
53 const p = os.posix;51 const p = os.posix;
...@@ -105,7 +103,7 @@ pub const IncrementingAllocator = struct {...@@ -105,7 +103,7 @@ pub const IncrementingAllocator = struct {
105 return self.bytes.len - self.end_index;103 return self.bytes.len - self.end_index;
106 }104 }
107105
108 fn alloc(allocator: &Allocator, n: usize, alignment: u29) %[]u8 {106 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
109 const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);107 const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);
110 const addr = @ptrToInt(&self.bytes[self.end_index]);108 const addr = @ptrToInt(&self.bytes[self.end_index]);
111 const rem = @rem(addr, alignment);109 const rem = @rem(addr, alignment);
...@@ -120,7 +118,7 @@ pub const IncrementingAllocator = struct {...@@ -120,7 +118,7 @@ pub const IncrementingAllocator = struct {
120 return result;118 return result;
121 }119 }
122120
123 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) %[]u8 {121 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
124 if (new_size <= old_mem.len) {122 if (new_size <= old_mem.len) {
125 return old_mem[0..new_size];123 return old_mem[0..new_size];
126 } else {124 } else {
std/io.zig+195-193
...@@ -26,31 +26,9 @@ test "import io tests" {...@@ -26,31 +26,9 @@ test "import io tests" {
26 }26 }
27}27}
2828
29/// The function received invalid input at runtime. An Invalid error means a29const GetStdIoErrs = os.WindowsGetStdHandleErrs;
30/// bug in the program that called the function.30
31error Invalid;31pub fn getStdErr() GetStdIoErrs!File {
32
33error DiskQuota;
34error FileTooBig;
35error Io;
36error NoSpaceLeft;
37error BadPerm;
38error BrokenPipe;
39error BadFd;
40error IsDir;
41error NotDir;
42error SymLinkLoop;
43error ProcessFdQuotaExceeded;
44error SystemFdQuotaExceeded;
45error NameTooLong;
46error NoDevice;
47error PathNotFound;
48error OutOfMemory;
49error Unseekable;
50error EndOfFile;
51error FilePosLargerThanPointerRange;
52
53pub fn getStdErr() %File {
54 const handle = if (is_windows)32 const handle = if (is_windows)
55 try os.windowsGetStdHandle(system.STD_ERROR_HANDLE)33 try os.windowsGetStdHandle(system.STD_ERROR_HANDLE)
56 else if (is_posix)34 else if (is_posix)
...@@ -60,7 +38,7 @@ pub fn getStdErr() %File {...@@ -60,7 +38,7 @@ pub fn getStdErr() %File {
60 return File.openHandle(handle);38 return File.openHandle(handle);
61}39}
6240
63pub fn getStdOut() %File {41pub fn getStdOut() GetStdIoErrs!File {
64 const handle = if (is_windows)42 const handle = if (is_windows)
65 try os.windowsGetStdHandle(system.STD_OUTPUT_HANDLE)43 try os.windowsGetStdHandle(system.STD_OUTPUT_HANDLE)
66 else if (is_posix)44 else if (is_posix)
...@@ -70,7 +48,7 @@ pub fn getStdOut() %File {...@@ -70,7 +48,7 @@ pub fn getStdOut() %File {
70 return File.openHandle(handle);48 return File.openHandle(handle);
71}49}
7250
73pub fn getStdIn() %File {51pub fn getStdIn() GetStdIoErrs!File {
74 const handle = if (is_windows)52 const handle = if (is_windows)
75 try os.windowsGetStdHandle(system.STD_INPUT_HANDLE)53 try os.windowsGetStdHandle(system.STD_INPUT_HANDLE)
76 else if (is_posix)54 else if (is_posix)
...@@ -83,18 +61,21 @@ pub fn getStdIn() %File {...@@ -83,18 +61,21 @@ pub fn getStdIn() %File {
83/// Implementation of InStream trait for File61/// Implementation of InStream trait for File
84pub const FileInStream = struct {62pub const FileInStream = struct {
85 file: &File,63 file: &File,
86 stream: InStream,64 stream: Stream,
65
66 pub const Error = @typeOf(File.read).ReturnType.ErrorSet;
67 pub const Stream = InStream(Error);
8768
88 pub fn init(file: &File) FileInStream {69 pub fn init(file: &File) FileInStream {
89 return FileInStream {70 return FileInStream {
90 .file = file,71 .file = file,
91 .stream = InStream {72 .stream = Stream {
92 .readFn = readFn,73 .readFn = readFn,
93 },74 },
94 };75 };
95 }76 }
9677
97 fn readFn(in_stream: &InStream, buffer: []u8) %usize {78 fn readFn(in_stream: &Stream, buffer: []u8) Error!usize {
98 const self = @fieldParentPtr(FileInStream, "stream", in_stream);79 const self = @fieldParentPtr(FileInStream, "stream", in_stream);
99 return self.file.read(buffer);80 return self.file.read(buffer);
100 }81 }
...@@ -103,18 +84,21 @@ pub const FileInStream = struct {...@@ -103,18 +84,21 @@ pub const FileInStream = struct {
103/// Implementation of OutStream trait for File84/// Implementation of OutStream trait for File
104pub const FileOutStream = struct {85pub const FileOutStream = struct {
105 file: &File,86 file: &File,
106 stream: OutStream,87 stream: Stream,
88
89 pub const Error = File.WriteError;
90 pub const Stream = OutStream(Error);
10791
108 pub fn init(file: &File) FileOutStream {92 pub fn init(file: &File) FileOutStream {
109 return FileOutStream {93 return FileOutStream {
110 .file = file,94 .file = file,
111 .stream = OutStream {95 .stream = Stream {
112 .writeFn = writeFn,96 .writeFn = writeFn,
113 },97 },
114 };98 };
115 }99 }
116100
117 fn writeFn(out_stream: &OutStream, bytes: []const u8) %void {101 fn writeFn(out_stream: &Stream, bytes: []const u8) !void {
118 const self = @fieldParentPtr(FileOutStream, "stream", out_stream);102 const self = @fieldParentPtr(FileOutStream, "stream", out_stream);
119 return self.file.write(bytes);103 return self.file.write(bytes);
120 }104 }
...@@ -124,12 +108,14 @@ pub const File = struct {...@@ -124,12 +108,14 @@ pub const File = struct {
124 /// The OS-specific file descriptor or file handle.108 /// The OS-specific file descriptor or file handle.
125 handle: os.FileHandle,109 handle: os.FileHandle,
126110
111 const OpenError = os.WindowsOpenError || os.PosixOpenError;
112
127 /// `path` may need to be copied in memory to add a null terminating byte. In this case113 /// `path` may need to be copied in memory to add a null terminating byte. In this case
128 /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed114 /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed
129 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.115 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.
130 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.116 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
131 /// Call close to clean up.117 /// Call close to clean up.
132 pub fn openRead(path: []const u8, allocator: ?&mem.Allocator) %File {118 pub fn openRead(path: []const u8, allocator: ?&mem.Allocator) OpenError!File {
133 if (is_posix) {119 if (is_posix) {
134 const flags = system.O_LARGEFILE|system.O_RDONLY;120 const flags = system.O_LARGEFILE|system.O_RDONLY;
135 const fd = try os.posixOpen(path, flags, 0, allocator);121 const fd = try os.posixOpen(path, flags, 0, allocator);
...@@ -144,7 +130,7 @@ pub const File = struct {...@@ -144,7 +130,7 @@ pub const File = struct {
144 }130 }
145131
146 /// Calls `openWriteMode` with 0o666 for the mode.132 /// Calls `openWriteMode` with 0o666 for the mode.
147 pub fn openWrite(path: []const u8, allocator: ?&mem.Allocator) %File {133 pub fn openWrite(path: []const u8, allocator: ?&mem.Allocator) !File {
148 return openWriteMode(path, 0o666, allocator);134 return openWriteMode(path, 0o666, allocator);
149135
150 }136 }
...@@ -154,7 +140,7 @@ pub const File = struct {...@@ -154,7 +140,7 @@ pub const File = struct {
154 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.140 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.
155 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.141 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
156 /// Call close to clean up.142 /// Call close to clean up.
157 pub fn openWriteMode(path: []const u8, mode: usize, allocator: ?&mem.Allocator) %File {143 pub fn openWriteMode(path: []const u8, mode: usize, allocator: ?&mem.Allocator) !File {
158 if (is_posix) {144 if (is_posix) {
159 const flags = system.O_LARGEFILE|system.O_WRONLY|system.O_CREAT|system.O_CLOEXEC|system.O_TRUNC;145 const flags = system.O_LARGEFILE|system.O_WRONLY|system.O_CREAT|system.O_CLOEXEC|system.O_TRUNC;
160 const fd = try os.posixOpen(path, flags, mode, allocator);146 const fd = try os.posixOpen(path, flags, mode, allocator);
...@@ -189,7 +175,7 @@ pub const File = struct {...@@ -189,7 +175,7 @@ pub const File = struct {
189 return os.isTty(self.handle);175 return os.isTty(self.handle);
190 }176 }
191177
192 pub fn seekForward(self: &File, amount: isize) %void {178 pub fn seekForward(self: &File, amount: isize) !void {
193 switch (builtin.os) {179 switch (builtin.os) {
194 Os.linux, Os.macosx, Os.ios => {180 Os.linux, Os.macosx, Os.ios => {
195 const result = system.lseek(self.handle, amount, system.SEEK_CUR);181 const result = system.lseek(self.handle, amount, system.SEEK_CUR);
...@@ -218,7 +204,7 @@ pub const File = struct {...@@ -218,7 +204,7 @@ pub const File = struct {
218 }204 }
219 }205 }
220206
221 pub fn seekTo(self: &File, pos: usize) %void {207 pub fn seekTo(self: &File, pos: usize) !void {
222 switch (builtin.os) {208 switch (builtin.os) {
223 Os.linux, Os.macosx, Os.ios => {209 Os.linux, Os.macosx, Os.ios => {
224 const ipos = try math.cast(isize, pos);210 const ipos = try math.cast(isize, pos);
...@@ -249,7 +235,7 @@ pub const File = struct {...@@ -249,7 +235,7 @@ pub const File = struct {
249 }235 }
250 }236 }
251237
252 pub fn getPos(self: &File) %usize {238 pub fn getPos(self: &File) !usize {
253 switch (builtin.os) {239 switch (builtin.os) {
254 Os.linux, Os.macosx, Os.ios => {240 Os.linux, Os.macosx, Os.ios => {
255 const result = system.lseek(self.handle, 0, system.SEEK_CUR);241 const result = system.lseek(self.handle, 0, system.SEEK_CUR);
...@@ -289,7 +275,7 @@ pub const File = struct {...@@ -289,7 +275,7 @@ pub const File = struct {
289 }275 }
290 }276 }
291277
292 pub fn getEndPos(self: &File) %usize {278 pub fn getEndPos(self: &File) !usize {
293 if (is_posix) {279 if (is_posix) {
294 var stat: system.Stat = undefined;280 var stat: system.Stat = undefined;
295 const err = system.getErrno(system.fstat(self.handle, &stat));281 const err = system.getErrno(system.fstat(self.handle, &stat));
...@@ -318,7 +304,9 @@ pub const File = struct {...@@ -318,7 +304,9 @@ pub const File = struct {
318 }304 }
319 }305 }
320306
321 pub fn read(self: &File, buffer: []u8) %usize {307 pub const ReadError = error {};
308
309 pub fn read(self: &File, buffer: []u8) !usize {
322 if (is_posix) {310 if (is_posix) {
323 var index: usize = 0;311 var index: usize = 0;
324 while (index < buffer.len) {312 while (index < buffer.len) {
...@@ -360,7 +348,9 @@ pub const File = struct {...@@ -360,7 +348,9 @@ pub const File = struct {
360 }348 }
361 }349 }
362350
363 fn write(self: &File, bytes: []const u8) %void {351 pub const WriteError = os.WindowsWriteError || os.PosixWriteError;
352
353 fn write(self: &File, bytes: []const u8) WriteError!void {
364 if (is_posix) {354 if (is_posix) {
365 try os.posixWrite(self.handle, bytes);355 try os.posixWrite(self.handle, bytes);
366 } else if (is_windows) {356 } else if (is_windows) {
...@@ -371,180 +361,183 @@ pub const File = struct {...@@ -371,180 +361,183 @@ pub const File = struct {
371 }361 }
372};362};
373363
374error StreamTooLong;364pub fn InStream(comptime Error: type) type {
375error EndOfStream;365 return struct {
376366 const Self = this;
377pub const InStream = struct {
378 /// Return the number of bytes read. If the number read is smaller than buf.len, it
379 /// means the stream reached the end. Reaching the end of a stream is not an error
380 /// condition.
381 readFn: fn(self: &InStream, buffer: []u8) %usize,
382
383 /// Replaces `buffer` contents by reading from the stream until it is finished.
384 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and
385 /// the contents read from the stream are lost.
386 pub fn readAllBuffer(self: &InStream, buffer: &Buffer, max_size: usize) %void {
387 try buffer.resize(0);
388
389 var actual_buf_len: usize = 0;
390 while (true) {
391 const dest_slice = buffer.toSlice()[actual_buf_len..];
392 const bytes_read = try self.readFn(self, dest_slice);
393 actual_buf_len += bytes_read;
394
395 if (bytes_read != dest_slice.len) {
396 buffer.shrink(actual_buf_len);
397 return;
398 }
399
400 const new_buf_size = math.min(max_size, actual_buf_len + os.page_size);
401 if (new_buf_size == actual_buf_len)
402 return error.StreamTooLong;
403 try buffer.resize(new_buf_size);
404 }
405 }
406367
407 /// Allocates enough memory to hold all the contents of the stream. If the allocated368 /// Return the number of bytes read. If the number read is smaller than buf.len, it
408 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.369 /// means the stream reached the end. Reaching the end of a stream is not an error
409 /// Caller owns returned memory.370 /// condition.
410 /// If this function returns an error, the contents from the stream read so far are lost.371 readFn: fn(self: &Self, buffer: []u8) Error!usize,
411 pub fn readAllAlloc(self: &InStream, allocator: &mem.Allocator, max_size: usize) %[]u8 {
412 var buf = Buffer.initNull(allocator);
413 defer buf.deinit();
414372
415 try self.readAllBuffer(&buf, max_size);373 /// Replaces `buffer` contents by reading from the stream until it is finished.
416 return buf.toOwnedSlice();374 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and
417 }375 /// the contents read from the stream are lost.
376 pub fn readAllBuffer(self: &Self, buffer: &Buffer, max_size: usize) !void {
377 try buffer.resize(0);
418378
419 /// Replaces `buffer` contents by reading from the stream until `delimiter` is found.379 var actual_buf_len: usize = 0;
420 /// Does not include the delimiter in the result.380 while (true) {
421 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents381 const dest_slice = buffer.toSlice()[actual_buf_len..];
422 /// read from the stream so far are lost.382 const bytes_read = try self.readFn(self, dest_slice);
423 pub fn readUntilDelimiterBuffer(self: &InStream, buffer: &Buffer, delimiter: u8, max_size: usize) %void {383 actual_buf_len += bytes_read;
424 try buf.resize(0);
425384
426 while (true) {385 if (bytes_read != dest_slice.len) {
427 var byte: u8 = try self.readByte();386 buffer.shrink(actual_buf_len);
387 return;
388 }
428389
429 if (byte == delimiter) {390 const new_buf_size = math.min(max_size, actual_buf_len + os.page_size);
430 return;391 if (new_buf_size == actual_buf_len)
392 return error.StreamTooLong;
393 try buffer.resize(new_buf_size);
431 }394 }
395 }
432396
433 if (buf.len() == max_size) {397 /// Allocates enough memory to hold all the contents of the stream. If the allocated
434 return error.StreamTooLong;398 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.
435 }399 /// Caller owns returned memory.
400 /// If this function returns an error, the contents from the stream read so far are lost.
401 pub fn readAllAlloc(self: &Self, allocator: &mem.Allocator, max_size: usize) ![]u8 {
402 var buf = Buffer.initNull(allocator);
403 defer buf.deinit();
436404
437 try buf.appendByte(byte);405 try self.readAllBuffer(&buf, max_size);
406 return buf.toOwnedSlice();
438 }407 }
439 }
440408
441 /// Allocates enough memory to read until `delimiter`. If the allocated409 /// Replaces `buffer` contents by reading from the stream until `delimiter` is found.
442 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.410 /// Does not include the delimiter in the result.
443 /// Caller owns returned memory.411 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents
444 /// If this function returns an error, the contents from the stream read so far are lost.412 /// read from the stream so far are lost.
445 pub fn readUntilDelimiterAlloc(self: &InStream, allocator: &mem.Allocator,413 pub fn readUntilDelimiterBuffer(self: &Self, buffer: &Buffer, delimiter: u8, max_size: usize) !void {
446 delimiter: u8, max_size: usize) %[]u8414 try buf.resize(0);
447 {
448 var buf = Buffer.initNull(allocator);
449 defer buf.deinit();
450
451 try self.readUntilDelimiterBuffer(self, &buf, delimiter, max_size);
452 return buf.toOwnedSlice();
453 }
454415
455 /// Returns the number of bytes read. If the number read is smaller than buf.len, it416 while (true) {
456 /// means the stream reached the end. Reaching the end of a stream is not an error417 var byte: u8 = try self.readByte();
457 /// condition.
458 pub fn read(self: &InStream, buffer: []u8) %usize {
459 return self.readFn(self, buffer);
460 }
461418
462 /// Same as `read` but end of stream returns `error.EndOfStream`.419 if (byte == delimiter) {
463 pub fn readNoEof(self: &InStream, buf: []u8) %void {420 return;
464 const amt_read = try self.read(buf);421 }
465 if (amt_read < buf.len) return error.EndOfStream;
466 }
467422
468 /// Reads 1 byte from the stream or returns `error.EndOfStream`.423 if (buf.len() == max_size) {
469 pub fn readByte(self: &InStream) %u8 {424 return error.StreamTooLong;
470 var result: [1]u8 = undefined;425 }
471 try self.readNoEof(result[0..]);
472 return result[0];
473 }
474426
475 /// Same as `readByte` except the returned byte is signed.427 try buf.appendByte(byte);
476 pub fn readByteSigned(self: &InStream) %i8 {428 }
477 return @bitCast(i8, try self.readByte());429 }
478 }
479430
480 pub fn readIntLe(self: &InStream, comptime T: type) %T {431 /// Allocates enough memory to read until `delimiter`. If the allocated
481 return self.readInt(builtin.Endian.Little, T);432 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.
482 }433 /// Caller owns returned memory.
434 /// If this function returns an error, the contents from the stream read so far are lost.
435 pub fn readUntilDelimiterAlloc(self: &Self, allocator: &mem.Allocator,
436 delimiter: u8, max_size: usize) ![]u8
437 {
438 var buf = Buffer.initNull(allocator);
439 defer buf.deinit();
440
441 try self.readUntilDelimiterBuffer(self, &buf, delimiter, max_size);
442 return buf.toOwnedSlice();
443 }
483444
484 pub fn readIntBe(self: &InStream, comptime T: type) %T {445 /// Returns the number of bytes read. If the number read is smaller than buf.len, it
485 return self.readInt(builtin.Endian.Big, T);446 /// means the stream reached the end. Reaching the end of a stream is not an error
486 }447 /// condition.
448 pub fn read(self: &Self, buffer: []u8) !usize {
449 return self.readFn(self, buffer);
450 }
487451
488 pub fn readInt(self: &InStream, endian: builtin.Endian, comptime T: type) %T {452 /// Same as `read` but end of stream returns `error.EndOfStream`.
489 var bytes: [@sizeOf(T)]u8 = undefined;453 pub fn readNoEof(self: &Self, buf: []u8) !void {
490 try self.readNoEof(bytes[0..]);454 const amt_read = try self.read(buf);
491 return mem.readInt(bytes, T, endian);455 if (amt_read < buf.len) return error.EndOfStream;
492 }456 }
493457
494 pub fn readVarInt(self: &InStream, endian: builtin.Endian, comptime T: type, size: usize) %T {458 /// Reads 1 byte from the stream or returns `error.EndOfStream`.
495 assert(size <= @sizeOf(T));459 pub fn readByte(self: &Self) !u8 {
496 assert(size <= 8);460 var result: [1]u8 = undefined;
497 var input_buf: [8]u8 = undefined;461 try self.readNoEof(result[0..]);
498 const input_slice = input_buf[0..size];462 return result[0];
499 try self.readNoEof(input_slice);463 }
500 return mem.readInt(input_slice, T, endian);
501 }
502464
465 /// Same as `readByte` except the returned byte is signed.
466 pub fn readByteSigned(self: &Self) !i8 {
467 return @bitCast(i8, try self.readByte());
468 }
503469
504};470 pub fn readIntLe(self: &Self, comptime T: type) !T {
471 return self.readInt(builtin.Endian.Little, T);
472 }
505473
506pub const OutStream = struct {474 pub fn readIntBe(self: &Self, comptime T: type) !T {
507 writeFn: fn(self: &OutStream, bytes: []const u8) %void,475 return self.readInt(builtin.Endian.Big, T);
476 }
508477
509 pub fn print(self: &OutStream, comptime format: []const u8, args: ...) %void {478 pub fn readInt(self: &Self, endian: builtin.Endian, comptime T: type) !T {
510 return std.fmt.format(self, self.writeFn, format, args);479 var bytes: [@sizeOf(T)]u8 = undefined;
511 }480 try self.readNoEof(bytes[0..]);
481 return mem.readInt(bytes, T, endian);
482 }
512483
513 pub fn write(self: &OutStream, bytes: []const u8) %void {484 pub fn readVarInt(self: &Self, endian: builtin.Endian, comptime T: type, size: usize) !T {
514 return self.writeFn(self, bytes);485 assert(size <= @sizeOf(T));
515 }486 assert(size <= 8);
487 var input_buf: [8]u8 = undefined;
488 const input_slice = input_buf[0..size];
489 try self.readNoEof(input_slice);
490 return mem.readInt(input_slice, T, endian);
491 }
492 };
493}
516494
517 pub fn writeByte(self: &OutStream, byte: u8) %void {495pub fn OutStream(comptime Error: type) type {
518 const slice = (&byte)[0..1];496 return struct {
519 return self.writeFn(self, slice);497 const Self = this;
520 }498
499 writeFn: fn(self: &Self, bytes: []const u8) Error!void,
521500
522 pub fn writeByteNTimes(self: &OutStream, byte: u8, n: usize) %void {501 pub fn print(self: &Self, comptime format: []const u8, args: ...) !void {
523 const slice = (&byte)[0..1];502 return std.fmt.format(self, error, self.writeFn, format, args);
524 var i: usize = 0;503 }
525 while (i < n) : (i += 1) {504
526 try self.writeFn(self, slice);505 pub fn write(self: &Self, bytes: []const u8) !void {
506 return self.writeFn(self, bytes);
507 }
508
509 pub fn writeByte(self: &Self, byte: u8) !void {
510 const slice = (&byte)[0..1];
511 return self.writeFn(self, slice);
527 }512 }
528 }513
529};514 pub fn writeByteNTimes(self: &Self, byte: u8, n: usize) !void {
515 const slice = (&byte)[0..1];
516 var i: usize = 0;
517 while (i < n) : (i += 1) {
518 try self.writeFn(self, slice);
519 }
520 }
521 };
522}
530523
531/// `path` may need to be copied in memory to add a null terminating byte. In this case524/// `path` may need to be copied in memory to add a null terminating byte. In this case
532/// a fixed size buffer of size `std.os.max_noalloc_path_len` is an attempted solution. If the fixed525/// a fixed size buffer of size `std.os.max_noalloc_path_len` is an attempted solution. If the fixed
533/// size buffer is too small, and the provided allocator is null, `error.NameTooLong` is returned.526/// size buffer is too small, and the provided allocator is null, `error.NameTooLong` is returned.
534/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.527/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
535pub fn writeFile(path: []const u8, data: []const u8, allocator: ?&mem.Allocator) %void {528pub fn writeFile(path: []const u8, data: []const u8, allocator: ?&mem.Allocator) !void {
536 var file = try File.openWrite(path, allocator);529 var file = try File.openWrite(path, allocator);
537 defer file.close();530 defer file.close();
538 try file.write(data);531 try file.write(data);
539}532}
540533
541/// On success, caller owns returned buffer.534/// On success, caller owns returned buffer.
542pub fn readFileAlloc(path: []const u8, allocator: &mem.Allocator) %[]u8 {535pub fn readFileAlloc(path: []const u8, allocator: &mem.Allocator) ![]u8 {
543 return readFileAllocExtra(path, allocator, 0);536 return readFileAllocExtra(path, allocator, 0);
544}537}
545/// On success, caller owns returned buffer.538/// On success, caller owns returned buffer.
546/// Allocates extra_len extra bytes at the end of the file buffer, which are uninitialized.539/// Allocates extra_len extra bytes at the end of the file buffer, which are uninitialized.
547pub fn readFileAllocExtra(path: []const u8, allocator: &mem.Allocator, extra_len: usize) %[]u8 {540pub fn readFileAllocExtra(path: []const u8, allocator: &mem.Allocator, extra_len: usize) ![]u8 {
548 var file = try File.openRead(path, allocator);541 var file = try File.openRead(path, allocator);
549 defer file.close();542 defer file.close();
550543
...@@ -557,21 +550,24 @@ pub fn readFileAllocExtra(path: []const u8, allocator: &mem.Allocator, extra_len...@@ -557,21 +550,24 @@ pub fn readFileAllocExtra(path: []const u8, allocator: &mem.Allocator, extra_len
557 return buf;550 return buf;
558}551}
559552
560pub const BufferedInStream = BufferedInStreamCustom(os.page_size);553pub fn BufferedInStream(comptime Error: type) type {
554 return BufferedInStreamCustom(os.page_size, Error);
555}
561556
562pub fn BufferedInStreamCustom(comptime buffer_size: usize) type {557pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) type {
563 return struct {558 return struct {
564 const Self = this;559 const Self = this;
560 const Stream = InStream(Error);
565561
566 pub stream: InStream,562 pub stream: Stream,
567563
568 unbuffered_in_stream: &InStream,564 unbuffered_in_stream: &Stream,
569565
570 buffer: [buffer_size]u8,566 buffer: [buffer_size]u8,
571 start_index: usize,567 start_index: usize,
572 end_index: usize,568 end_index: usize,
573569
574 pub fn init(unbuffered_in_stream: &InStream) Self {570 pub fn init(unbuffered_in_stream: &Stream) Self {
575 return Self {571 return Self {
576 .unbuffered_in_stream = unbuffered_in_stream,572 .unbuffered_in_stream = unbuffered_in_stream,
577 .buffer = undefined,573 .buffer = undefined,
...@@ -583,13 +579,13 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize) type {...@@ -583,13 +579,13 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize) type {
583 .start_index = buffer_size,579 .start_index = buffer_size,
584 .end_index = buffer_size,580 .end_index = buffer_size,
585581
586 .stream = InStream {582 .stream = Stream {
587 .readFn = readFn,583 .readFn = readFn,
588 },584 },
589 };585 };
590 }586 }
591587
592 fn readFn(in_stream: &InStream, dest: []u8) %usize {588 fn readFn(in_stream: &Stream, dest: []u8) !usize {
593 const self = @fieldParentPtr(Self, "stream", in_stream);589 const self = @fieldParentPtr(Self, "stream", in_stream);
594590
595 var dest_index: usize = 0;591 var dest_index: usize = 0;
...@@ -628,31 +624,34 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize) type {...@@ -628,31 +624,34 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize) type {
628 };624 };
629}625}
630626
631pub const BufferedOutStream = BufferedOutStreamCustom(os.page_size);627pub fn BufferedOutStream(comptime Error: type) type {
628 return BufferedOutStreamCustom(os.page_size, Error);
629}
632630
633pub fn BufferedOutStreamCustom(comptime buffer_size: usize) type {631pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime Error: type) type {
634 return struct {632 return struct {
635 const Self = this;633 const Self = this;
634 const Stream = OutStream(Error);
636635
637 pub stream: OutStream,636 pub stream: Stream,
638637
639 unbuffered_out_stream: &OutStream,638 unbuffered_out_stream: &Stream,
640639
641 buffer: [buffer_size]u8,640 buffer: [buffer_size]u8,
642 index: usize,641 index: usize,
643642
644 pub fn init(unbuffered_out_stream: &OutStream) Self {643 pub fn init(unbuffered_out_stream: &Stream) Self {
645 return Self {644 return Self {
646 .unbuffered_out_stream = unbuffered_out_stream,645 .unbuffered_out_stream = unbuffered_out_stream,
647 .buffer = undefined,646 .buffer = undefined,
648 .index = 0,647 .index = 0,
649 .stream = OutStream {648 .stream = Stream {
650 .writeFn = writeFn,649 .writeFn = writeFn,
651 },650 },
652 };651 };
653 }652 }
654653
655 pub fn flush(self: &Self) %void {654 pub fn flush(self: &Self) !void {
656 if (self.index == 0)655 if (self.index == 0)
657 return;656 return;
658657
...@@ -660,7 +659,7 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize) type {...@@ -660,7 +659,7 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize) type {
660 self.index = 0;659 self.index = 0;
661 }660 }
662661
663 fn writeFn(out_stream: &OutStream, bytes: []const u8) %void {662 fn writeFn(out_stream: &Stream, bytes: []const u8) !void {
664 const self = @fieldParentPtr(Self, "stream", out_stream);663 const self = @fieldParentPtr(Self, "stream", out_stream);
665664
666 if (bytes.len >= self.buffer.len) {665 if (bytes.len >= self.buffer.len) {
...@@ -687,18 +686,21 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize) type {...@@ -687,18 +686,21 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize) type {
687/// Implementation of OutStream trait for Buffer686/// Implementation of OutStream trait for Buffer
688pub const BufferOutStream = struct {687pub const BufferOutStream = struct {
689 buffer: &Buffer,688 buffer: &Buffer,
690 stream: OutStream,689 stream: Stream,
690
691 pub const Error = error{OutOfMemory};
692 pub const Stream = OutStream(Error);
691693
692 pub fn init(buffer: &Buffer) BufferOutStream {694 pub fn init(buffer: &Buffer) BufferOutStream {
693 return BufferOutStream {695 return BufferOutStream {
694 .buffer = buffer,696 .buffer = buffer,
695 .stream = OutStream {697 .stream = Stream {
696 .writeFn = writeFn,698 .writeFn = writeFn,
697 },699 },
698 };700 };
699 }701 }
700702
701 fn writeFn(out_stream: &OutStream, bytes: []const u8) %void {703 fn writeFn(out_stream: &Stream, bytes: []const u8) !void {
702 const self = @fieldParentPtr(BufferOutStream, "stream", out_stream);704 const self = @fieldParentPtr(BufferOutStream, "stream", out_stream);
703 return self.buffer.append(bytes);705 return self.buffer.append(bytes);
704 }706 }
std/io_test.zig+2-2
...@@ -17,7 +17,7 @@ test "write a file, read it, then delete it" {...@@ -17,7 +17,7 @@ test "write a file, read it, then delete it" {
17 defer file.close();17 defer file.close();
1818
19 var file_out_stream = io.FileOutStream.init(&file);19 var file_out_stream = io.FileOutStream.init(&file);
20 var buf_stream = io.BufferedOutStream.init(&file_out_stream.stream);20 var buf_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream);
21 const st = &buf_stream.stream;21 const st = &buf_stream.stream;
22 try st.print("begin");22 try st.print("begin");
23 try st.write(data[0..]);23 try st.write(data[0..]);
...@@ -33,7 +33,7 @@ test "write a file, read it, then delete it" {...@@ -33,7 +33,7 @@ test "write a file, read it, then delete it" {
33 assert(file_size == expected_file_size);33 assert(file_size == expected_file_size);
3434
35 var file_in_stream = io.FileInStream.init(&file);35 var file_in_stream = io.FileInStream.init(&file);
36 var buf_stream = io.BufferedInStream.init(&file_in_stream.stream);36 var buf_stream = io.BufferedInStream(io.FileInStream.Error).init(&file_in_stream.stream);
37 const st = &buf_stream.stream;37 const st = &buf_stream.stream;
38 const contents = try st.readAllAlloc(allocator, 2 * 1024);38 const contents = try st.readAllAlloc(allocator, 2 * 1024);
39 defer allocator.free(contents);39 defer allocator.free(contents);
std/linked_list.zig+2-2
...@@ -190,7 +190,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na...@@ -190,7 +190,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
190 ///190 ///
191 /// Returns:191 /// Returns:
192 /// A pointer to the new node.192 /// A pointer to the new node.
193 pub fn allocateNode(list: &Self, allocator: &Allocator) %&Node {193 pub fn allocateNode(list: &Self, allocator: &Allocator) !&Node {
194 comptime assert(!isIntrusive());194 comptime assert(!isIntrusive());
195 return allocator.create(Node);195 return allocator.create(Node);
196 }196 }
...@@ -213,7 +213,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na...@@ -213,7 +213,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
213 ///213 ///
214 /// Returns:214 /// Returns:
215 /// A pointer to the new node.215 /// A pointer to the new node.
216 pub fn createNode(list: &Self, data: &const T, allocator: &Allocator) %&Node {216 pub fn createNode(list: &Self, data: &const T, allocator: &Allocator) !&Node {
217 comptime assert(!isIntrusive());217 comptime assert(!isIntrusive());
218 var node = try list.allocateNode(allocator);218 var node = try list.allocateNode(allocator);
219 *node = Node.init(data);219 *node = Node.init(data);
std/math/index.zig+13-31
...@@ -191,30 +191,26 @@ test "math.max" {...@@ -191,30 +191,26 @@ test "math.max" {
191 assert(max(i32(-1), i32(2)) == 2);191 assert(max(i32(-1), i32(2)) == 2);
192}192}
193193
194error Overflow;194pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) {
195pub fn mul(comptime T: type, a: T, b: T) %T {
196 var answer: T = undefined;195 var answer: T = undefined;
197 return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer;196 return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer;
198}197}
199198
200error Overflow;199pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) {
201pub fn add(comptime T: type, a: T, b: T) %T {
202 var answer: T = undefined;200 var answer: T = undefined;
203 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;201 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
204}202}
205203
206error Overflow;204pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) {
207pub fn sub(comptime T: type, a: T, b: T) %T {
208 var answer: T = undefined;205 var answer: T = undefined;
209 return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer;206 return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer;
210}207}
211208
212pub fn negate(x: var) %@typeOf(x) {209pub fn negate(x: var) !@typeOf(x) {
213 return sub(@typeOf(x), 0, x);210 return sub(@typeOf(x), 0, x);
214}211}
215212
216error Overflow;213pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {
217pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) %T {
218 var answer: T = undefined;214 var answer: T = undefined;
219 return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer;215 return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer;
220}216}
...@@ -323,8 +319,7 @@ fn testOverflow() void {...@@ -323,8 +319,7 @@ fn testOverflow() void {
323}319}
324320
325321
326error Overflow;322pub fn absInt(x: var) !@typeOf(x) {
327pub fn absInt(x: var) %@typeOf(x) {
328 const T = @typeOf(x);323 const T = @typeOf(x);
329 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt324 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
330 comptime assert(T.is_signed); // must pass a signed integer to absInt325 comptime assert(T.is_signed); // must pass a signed integer to absInt
...@@ -347,9 +342,7 @@ fn testAbsInt() void {...@@ -347,9 +342,7 @@ fn testAbsInt() void {
347342
348pub const absFloat = @import("fabs.zig").fabs;343pub const absFloat = @import("fabs.zig").fabs;
349344
350error DivisionByZero;345pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {
351error Overflow;
352pub fn divTrunc(comptime T: type, numerator: T, denominator: T) %T {
353 @setRuntimeSafety(false);346 @setRuntimeSafety(false);
354 if (denominator == 0)347 if (denominator == 0)
355 return error.DivisionByZero;348 return error.DivisionByZero;
...@@ -372,9 +365,7 @@ fn testDivTrunc() void {...@@ -372,9 +365,7 @@ fn testDivTrunc() void {
372 assert((divTrunc(f32, -5.0, 3.0) catch unreachable) == -1.0);365 assert((divTrunc(f32, -5.0, 3.0) catch unreachable) == -1.0);
373}366}
374367
375error DivisionByZero;368pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T {
376error Overflow;
377pub fn divFloor(comptime T: type, numerator: T, denominator: T) %T {
378 @setRuntimeSafety(false);369 @setRuntimeSafety(false);
379 if (denominator == 0)370 if (denominator == 0)
380 return error.DivisionByZero;371 return error.DivisionByZero;
...@@ -397,10 +388,7 @@ fn testDivFloor() void {...@@ -397,10 +388,7 @@ fn testDivFloor() void {
397 assert((divFloor(f32, -5.0, 3.0) catch unreachable) == -2.0);388 assert((divFloor(f32, -5.0, 3.0) catch unreachable) == -2.0);
398}389}
399390
400error DivisionByZero;391pub fn divExact(comptime T: type, numerator: T, denominator: T) !T {
401error Overflow;
402error UnexpectedRemainder;
403pub fn divExact(comptime T: type, numerator: T, denominator: T) %T {
404 @setRuntimeSafety(false);392 @setRuntimeSafety(false);
405 if (denominator == 0)393 if (denominator == 0)
406 return error.DivisionByZero;394 return error.DivisionByZero;
...@@ -428,9 +416,7 @@ fn testDivExact() void {...@@ -428,9 +416,7 @@ fn testDivExact() void {
428 if (divExact(f32, 5.0, 2.0)) |_| unreachable else |err| assert(err == error.UnexpectedRemainder);416 if (divExact(f32, 5.0, 2.0)) |_| unreachable else |err| assert(err == error.UnexpectedRemainder);
429}417}
430418
431error DivisionByZero;419pub fn mod(comptime T: type, numerator: T, denominator: T) !T {
432error NegativeDenominator;
433pub fn mod(comptime T: type, numerator: T, denominator: T) %T {
434 @setRuntimeSafety(false);420 @setRuntimeSafety(false);
435 if (denominator == 0)421 if (denominator == 0)
436 return error.DivisionByZero;422 return error.DivisionByZero;
...@@ -455,9 +441,7 @@ fn testMod() void {...@@ -455,9 +441,7 @@ fn testMod() void {
455 if (mod(f32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);441 if (mod(f32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);
456}442}
457443
458error DivisionByZero;444pub fn rem(comptime T: type, numerator: T, denominator: T) !T {
459error NegativeDenominator;
460pub fn rem(comptime T: type, numerator: T, denominator: T) %T {
461 @setRuntimeSafety(false);445 @setRuntimeSafety(false);
462 if (denominator == 0)446 if (denominator == 0)
463 return error.DivisionByZero;447 return error.DivisionByZero;
...@@ -505,8 +489,7 @@ test "math.absCast" {...@@ -505,8 +489,7 @@ test "math.absCast" {
505489
506/// Returns the negation of the integer parameter.490/// Returns the negation of the integer parameter.
507/// Result is a signed integer.491/// Result is a signed integer.
508error Overflow;492pub fn negateCast(x: var) !@IntType(true, @typeOf(x).bit_count) {
509pub fn negateCast(x: var) %@IntType(true, @typeOf(x).bit_count) {
510 if (@typeOf(x).is_signed)493 if (@typeOf(x).is_signed)
511 return negate(x);494 return negate(x);
512495
...@@ -532,8 +515,7 @@ test "math.negateCast" {...@@ -532,8 +515,7 @@ test "math.negateCast" {
532515
533/// Cast an integer to a different integer type. If the value doesn't fit, 516/// Cast an integer to a different integer type. If the value doesn't fit,
534/// return an error.517/// return an error.
535error Overflow;518pub fn cast(comptime T: type, x: var) !T {
536pub fn cast(comptime T: type, x: var) %T {
537 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer519 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer
538 if (x > @maxValue(T)) {520 if (x > @maxValue(T)) {
539 return error.Overflow;521 return error.Overflow;
std/mem.zig+15-15
...@@ -4,13 +4,13 @@ const assert = debug.assert;...@@ -4,13 +4,13 @@ const assert = debug.assert;
4const math = std.math;4const math = std.math;
5const builtin = @import("builtin");5const builtin = @import("builtin");
66
7error OutOfMemory;
8
9pub const Allocator = struct {7pub const Allocator = struct {
8 const Error = error {OutOfMemory};
9
10 /// Allocate byte_count bytes and return them in a slice, with the10 /// Allocate byte_count bytes and return them in a slice, with the
11 /// slice's pointer aligned at least to alignment bytes.11 /// slice's pointer aligned at least to alignment bytes.
12 /// The returned newly allocated memory is undefined.12 /// The returned newly allocated memory is undefined.
13 allocFn: fn (self: &Allocator, byte_count: usize, alignment: u29) %[]u8,13 allocFn: fn (self: &Allocator, byte_count: usize, alignment: u29) Error![]u8,
1414
15 /// If `new_byte_count > old_mem.len`:15 /// If `new_byte_count > old_mem.len`:
16 /// * `old_mem.len` is the same as what was returned from allocFn or reallocFn.16 /// * `old_mem.len` is the same as what was returned from allocFn or reallocFn.
...@@ -21,12 +21,12 @@ pub const Allocator = struct {...@@ -21,12 +21,12 @@ pub const Allocator = struct {
21 /// * alignment <= alignment of old_mem.ptr21 /// * alignment <= alignment of old_mem.ptr
22 ///22 ///
23 /// The returned newly allocated memory is undefined.23 /// The returned newly allocated memory is undefined.
24 reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) %[]u8,24 reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) Error![]u8,
2525
26 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`26 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
27 freeFn: fn (self: &Allocator, old_mem: []u8) void,27 freeFn: fn (self: &Allocator, old_mem: []u8) void,
2828
29 fn create(self: &Allocator, comptime T: type) %&T {29 fn create(self: &Allocator, comptime T: type) !&T {
30 const slice = try self.alloc(T, 1);30 const slice = try self.alloc(T, 1);
31 return &slice[0];31 return &slice[0];
32 }32 }
...@@ -35,14 +35,14 @@ pub const Allocator = struct {...@@ -35,14 +35,14 @@ pub const Allocator = struct {
35 self.free(ptr[0..1]);35 self.free(ptr[0..1]);
36 }36 }
3737
38 fn alloc(self: &Allocator, comptime T: type, n: usize) %[]T {38 fn alloc(self: &Allocator, comptime T: type, n: usize) ![]T {
39 return self.alignedAlloc(T, @alignOf(T), n);39 return self.alignedAlloc(T, @alignOf(T), n);
40 }40 }
4141
42 fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29,42 fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29,
43 n: usize) %[]align(alignment) T43 n: usize) ![]align(alignment) T
44 {44 {
45 const byte_count = try math.mul(usize, @sizeOf(T), n);45 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
46 const byte_slice = try self.allocFn(self, byte_count, alignment);46 const byte_slice = try self.allocFn(self, byte_count, alignment);
47 // This loop should get optimized out in ReleaseFast mode47 // This loop should get optimized out in ReleaseFast mode
48 for (byte_slice) |*byte| {48 for (byte_slice) |*byte| {
...@@ -51,19 +51,19 @@ pub const Allocator = struct {...@@ -51,19 +51,19 @@ pub const Allocator = struct {
51 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));51 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
52 }52 }
5353
54 fn realloc(self: &Allocator, comptime T: type, old_mem: []T, n: usize) %[]T {54 fn realloc(self: &Allocator, comptime T: type, old_mem: []T, n: usize) ![]T {
55 return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);55 return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
56 }56 }
5757
58 fn alignedRealloc(self: &Allocator, comptime T: type, comptime alignment: u29,58 fn alignedRealloc(self: &Allocator, comptime T: type, comptime alignment: u29,
59 old_mem: []align(alignment) T, n: usize) %[]align(alignment) T59 old_mem: []align(alignment) T, n: usize) ![]align(alignment) T
60 {60 {
61 if (old_mem.len == 0) {61 if (old_mem.len == 0) {
62 return self.alloc(T, n);62 return self.alloc(T, n);
63 }63 }
6464
65 const old_byte_slice = ([]u8)(old_mem);65 const old_byte_slice = ([]u8)(old_mem);
66 const byte_count = try math.mul(usize, @sizeOf(T), n);66 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
67 const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment);67 const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment);
68 // This loop should get optimized out in ReleaseFast mode68 // This loop should get optimized out in ReleaseFast mode
69 for (byte_slice[old_byte_slice.len..]) |*byte| {69 for (byte_slice[old_byte_slice.len..]) |*byte| {
...@@ -123,7 +123,7 @@ pub const FixedBufferAllocator = struct {...@@ -123,7 +123,7 @@ pub const FixedBufferAllocator = struct {
123 };123 };
124 }124 }
125125
126 fn alloc(allocator: &Allocator, n: usize, alignment: u29) %[]u8 {126 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
127 const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator);127 const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator);
128 const addr = @ptrToInt(&self.buffer[self.end_index]);128 const addr = @ptrToInt(&self.buffer[self.end_index]);
129 const rem = @rem(addr, alignment);129 const rem = @rem(addr, alignment);
...@@ -138,7 +138,7 @@ pub const FixedBufferAllocator = struct {...@@ -138,7 +138,7 @@ pub const FixedBufferAllocator = struct {
138 return result;138 return result;
139 }139 }
140140
141 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) %[]u8 {141 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
142 if (new_size <= old_mem.len) {142 if (new_size <= old_mem.len) {
143 return old_mem[0..new_size];143 return old_mem[0..new_size];
144 } else {144 } else {
...@@ -197,7 +197,7 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {...@@ -197,7 +197,7 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
197}197}
198198
199/// Copies ::m to newly allocated memory. Caller is responsible to free it.199/// Copies ::m to newly allocated memory. Caller is responsible to free it.
200pub fn dupe(allocator: &Allocator, comptime T: type, m: []const T) %[]T {200pub fn dupe(allocator: &Allocator, comptime T: type, m: []const T) ![]T {
201 const new_buf = try allocator.alloc(T, m.len);201 const new_buf = try allocator.alloc(T, m.len);
202 copy(T, new_buf, m);202 copy(T, new_buf, m);
203 return new_buf;203 return new_buf;
...@@ -428,7 +428,7 @@ const SplitIterator = struct {...@@ -428,7 +428,7 @@ const SplitIterator = struct {
428428
429/// Naively combines a series of strings with a separator.429/// Naively combines a series of strings with a separator.
430/// Allocates memory for the result, which must be freed by the caller.430/// Allocates memory for the result, which must be freed by the caller.
431pub fn join(allocator: &Allocator, sep: u8, strings: ...) %[]u8 {431pub fn join(allocator: &Allocator, sep: u8, strings: ...) ![]u8 {
432 comptime assert(strings.len >= 1);432 comptime assert(strings.len >= 1);
433 var total_strings_len: usize = strings.len; // 1 sep per string433 var total_strings_len: usize = strings.len; // 1 sep per string
434 {434 {
std/net.zig+9-25
...@@ -5,19 +5,10 @@ const endian = std.endian;...@@ -5,19 +5,10 @@ const endian = std.endian;
55
6// TODO don't trust this file, it bit rotted. start over6// TODO don't trust this file, it bit rotted. start over
77
8error SigInterrupt;
9error Io;
10error TimedOut;
11error ConnectionReset;
12error ConnectionRefused;
13error OutOfMemory;
14error NotSocket;
15error BadFd;
16
17const Connection = struct {8const Connection = struct {
18 socket_fd: i32,9 socket_fd: i32,
1910
20 pub fn send(c: Connection, buf: []const u8) %usize {11 pub fn send(c: Connection, buf: []const u8) !usize {
21 const send_ret = linux.sendto(c.socket_fd, buf.ptr, buf.len, 0, null, 0);12 const send_ret = linux.sendto(c.socket_fd, buf.ptr, buf.len, 0, null, 0);
22 const send_err = linux.getErrno(send_ret);13 const send_err = linux.getErrno(send_ret);
23 switch (send_err) {14 switch (send_err) {
...@@ -31,7 +22,7 @@ const Connection = struct {...@@ -31,7 +22,7 @@ const Connection = struct {
31 }22 }
32 }23 }
3324
34 pub fn recv(c: Connection, buf: []u8) %[]u8 {25 pub fn recv(c: Connection, buf: []u8) ![]u8 {
35 const recv_ret = linux.recvfrom(c.socket_fd, buf.ptr, buf.len, 0, null, null);26 const recv_ret = linux.recvfrom(c.socket_fd, buf.ptr, buf.len, 0, null, null);
36 const recv_err = linux.getErrno(recv_ret);27 const recv_err = linux.getErrno(recv_ret);
37 switch (recv_err) {28 switch (recv_err) {
...@@ -48,7 +39,7 @@ const Connection = struct {...@@ -48,7 +39,7 @@ const Connection = struct {
48 }39 }
49 }40 }
5041
51 pub fn close(c: Connection) %void {42 pub fn close(c: Connection) !void {
52 switch (linux.getErrno(linux.close(c.socket_fd))) {43 switch (linux.getErrno(linux.close(c.socket_fd))) {
53 0 => return,44 0 => return,
54 linux.EBADF => unreachable,45 linux.EBADF => unreachable,
...@@ -66,7 +57,7 @@ const Address = struct {...@@ -66,7 +57,7 @@ const Address = struct {
66 sort_key: i32,57 sort_key: i32,
67};58};
6859
69pub fn lookup(hostname: []const u8, out_addrs: []Address) %[]Address {60pub fn lookup(hostname: []const u8, out_addrs: []Address) ![]Address {
70 if (hostname.len == 0) {61 if (hostname.len == 0) {
7162
72 unreachable; // TODO63 unreachable; // TODO
...@@ -75,7 +66,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) %[]Address {...@@ -75,7 +66,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) %[]Address {
75 unreachable; // TODO66 unreachable; // TODO
76}67}
7768
78pub fn connectAddr(addr: &Address, port: u16) %Connection {69pub fn connectAddr(addr: &Address, port: u16) !Connection {
79 const socket_ret = linux.socket(addr.family, linux.SOCK_STREAM, linux.PROTO_tcp);70 const socket_ret = linux.socket(addr.family, linux.SOCK_STREAM, linux.PROTO_tcp);
80 const socket_err = linux.getErrno(socket_ret);71 const socket_err = linux.getErrno(socket_ret);
81 if (socket_err > 0) {72 if (socket_err > 0) {
...@@ -118,7 +109,7 @@ pub fn connectAddr(addr: &Address, port: u16) %Connection {...@@ -118,7 +109,7 @@ pub fn connectAddr(addr: &Address, port: u16) %Connection {
118 };109 };
119}110}
120111
121pub fn connect(hostname: []const u8, port: u16) %Connection {112pub fn connect(hostname: []const u8, port: u16) !Connection {
122 var addrs_buf: [1]Address = undefined;113 var addrs_buf: [1]Address = undefined;
123 const addrs_slice = try lookup(hostname, addrs_buf[0..]);114 const addrs_slice = try lookup(hostname, addrs_buf[0..]);
124 const main_addr = &addrs_slice[0];115 const main_addr = &addrs_slice[0];
...@@ -126,9 +117,7 @@ pub fn connect(hostname: []const u8, port: u16) %Connection {...@@ -126,9 +117,7 @@ pub fn connect(hostname: []const u8, port: u16) %Connection {
126 return connectAddr(main_addr, port);117 return connectAddr(main_addr, port);
127}118}
128119
129error InvalidIpLiteral;120pub fn parseIpLiteral(buf: []const u8) !Address {
130
131pub fn parseIpLiteral(buf: []const u8) %Address {
132121
133 return error.InvalidIpLiteral;122 return error.InvalidIpLiteral;
134}123}
...@@ -146,12 +135,7 @@ fn hexDigit(c: u8) u8 {...@@ -146,12 +135,7 @@ fn hexDigit(c: u8) u8 {
146 }135 }
147}136}
148137
149error InvalidChar;138fn parseIp6(buf: []const u8) !Address {
150error Overflow;
151error JunkAtEnd;
152error Incomplete;
153
154fn parseIp6(buf: []const u8) %Address {
155 var result: Address = undefined;139 var result: Address = undefined;
156 result.family = linux.AF_INET6;140 result.family = linux.AF_INET6;
157 result.scope_id = 0;141 result.scope_id = 0;
...@@ -232,7 +216,7 @@ fn parseIp6(buf: []const u8) %Address {...@@ -232,7 +216,7 @@ fn parseIp6(buf: []const u8) %Address {
232 return error.Incomplete;216 return error.Incomplete;
233}217}
234218
235fn parseIp4(buf: []const u8) %u32 {219fn parseIp4(buf: []const u8) !u32 {
236 var result: u32 = undefined;220 var result: u32 = undefined;
237 const out_ptr = ([]u8)((&result)[0..1]);221 const out_ptr = ([]u8)((&result)[0..1]);
238222
std/os/child_process.zig+49-34
...@@ -13,10 +13,6 @@ const builtin = @import("builtin");...@@ -13,10 +13,6 @@ const builtin = @import("builtin");
13const Os = builtin.Os;13const Os = builtin.Os;
14const LinkedList = std.LinkedList;14const LinkedList = std.LinkedList;
1515
16error PermissionDenied;
17error ProcessNotFound;
18error InvalidName;
19
20var children_nodes = LinkedList(&ChildProcess).init();16var children_nodes = LinkedList(&ChildProcess).init();
2117
22const is_windows = builtin.os == Os.windows;18const is_windows = builtin.os == Os.windows;
...@@ -32,7 +28,7 @@ pub const ChildProcess = struct {...@@ -32,7 +28,7 @@ pub const ChildProcess = struct {
32 pub stdout: ?io.File,28 pub stdout: ?io.File,
33 pub stderr: ?io.File,29 pub stderr: ?io.File,
3430
35 pub term: ?%Term,31 pub term: ?(SpawnError!Term),
3632
37 pub argv: []const []const u8,33 pub argv: []const []const u8,
3834
...@@ -58,6 +54,25 @@ pub const ChildProcess = struct {...@@ -58,6 +54,25 @@ pub const ChildProcess = struct {
58 err_pipe: if (is_windows) void else [2]i32,54 err_pipe: if (is_windows) void else [2]i32,
59 llnode: if (is_windows) void else LinkedList(&ChildProcess).Node,55 llnode: if (is_windows) void else LinkedList(&ChildProcess).Node,
6056
57 pub const SpawnError = error {
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,
74 };
75
61 pub const Term = union(enum) {76 pub const Term = union(enum) {
62 Exited: i32,77 Exited: i32,
63 Signal: i32,78 Signal: i32,
...@@ -74,7 +89,7 @@ pub const ChildProcess = struct {...@@ -74,7 +89,7 @@ pub const ChildProcess = struct {
7489
75 /// First argument in argv is the executable.90 /// First argument in argv is the executable.
76 /// On success must call deinit.91 /// On success must call deinit.
77 pub fn init(argv: []const []const u8, allocator: &mem.Allocator) %&ChildProcess {92 pub fn init(argv: []const []const u8, allocator: &mem.Allocator) !&ChildProcess {
78 const child = try allocator.create(ChildProcess);93 const child = try allocator.create(ChildProcess);
79 errdefer allocator.destroy(child);94 errdefer allocator.destroy(child);
8095
...@@ -103,7 +118,7 @@ pub const ChildProcess = struct {...@@ -103,7 +118,7 @@ pub const ChildProcess = struct {
103 return child;118 return child;
104 }119 }
105120
106 pub fn setUserName(self: &ChildProcess, name: []const u8) %void {121 pub fn setUserName(self: &ChildProcess, name: []const u8) !void {
107 const user_info = try os.getUserInfo(name);122 const user_info = try os.getUserInfo(name);
108 self.uid = user_info.uid;123 self.uid = user_info.uid;
109 self.gid = user_info.gid;124 self.gid = user_info.gid;
...@@ -111,7 +126,7 @@ pub const ChildProcess = struct {...@@ -111,7 +126,7 @@ pub const ChildProcess = struct {
111126
112 /// onTerm can be called before `spawn` returns.127 /// onTerm can be called before `spawn` returns.
113 /// On success must call `kill` or `wait`.128 /// On success must call `kill` or `wait`.
114 pub fn spawn(self: &ChildProcess) %void {129 pub fn spawn(self: &ChildProcess) !void {
115 if (is_windows) {130 if (is_windows) {
116 return self.spawnWindows();131 return self.spawnWindows();
117 } else {132 } else {
...@@ -119,13 +134,13 @@ pub const ChildProcess = struct {...@@ -119,13 +134,13 @@ pub const ChildProcess = struct {
119 }134 }
120 }135 }
121136
122 pub fn spawnAndWait(self: &ChildProcess) %Term {137 pub fn spawnAndWait(self: &ChildProcess) !Term {
123 try self.spawn();138 try self.spawn();
124 return self.wait();139 return self.wait();
125 }140 }
126141
127 /// Forcibly terminates child process and then cleans up all resources.142 /// Forcibly terminates child process and then cleans up all resources.
128 pub fn kill(self: &ChildProcess) %Term {143 pub fn kill(self: &ChildProcess) !Term {
129 if (is_windows) {144 if (is_windows) {
130 return self.killWindows(1);145 return self.killWindows(1);
131 } else {146 } else {
...@@ -133,7 +148,7 @@ pub const ChildProcess = struct {...@@ -133,7 +148,7 @@ pub const ChildProcess = struct {
133 }148 }
134 }149 }
135150
136 pub fn killWindows(self: &ChildProcess, exit_code: windows.UINT) %Term {151 pub fn killWindows(self: &ChildProcess, exit_code: windows.UINT) !Term {
137 if (self.term) |term| {152 if (self.term) |term| {
138 self.cleanupStreams();153 self.cleanupStreams();
139 return term;154 return term;
...@@ -145,11 +160,11 @@ pub const ChildProcess = struct {...@@ -145,11 +160,11 @@ pub const ChildProcess = struct {
145 else => os.unexpectedErrorWindows(err),160 else => os.unexpectedErrorWindows(err),
146 };161 };
147 }162 }
148 self.waitUnwrappedWindows();163 try self.waitUnwrappedWindows();
149 return ??self.term;164 return ??self.term;
150 }165 }
151166
152 pub fn killPosix(self: &ChildProcess) %Term {167 pub fn killPosix(self: &ChildProcess) !Term {
153 block_SIGCHLD();168 block_SIGCHLD();
154 defer restore_SIGCHLD();169 defer restore_SIGCHLD();
155170
...@@ -172,7 +187,7 @@ pub const ChildProcess = struct {...@@ -172,7 +187,7 @@ pub const ChildProcess = struct {
172 }187 }
173188
174 /// Blocks until child process terminates and then cleans up all resources.189 /// Blocks until child process terminates and then cleans up all resources.
175 pub fn wait(self: &ChildProcess) %Term {190 pub fn wait(self: &ChildProcess) !Term {
176 if (is_windows) {191 if (is_windows) {
177 return self.waitWindows();192 return self.waitWindows();
178 } else {193 } else {
...@@ -189,7 +204,7 @@ pub const ChildProcess = struct {...@@ -189,7 +204,7 @@ pub const ChildProcess = struct {
189 /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.204 /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.
190 /// If it succeeds, the caller owns result.stdout and result.stderr memory.205 /// If it succeeds, the caller owns result.stdout and result.stderr memory.
191 pub fn exec(allocator: &mem.Allocator, argv: []const []const u8, cwd: ?[]const u8,206 pub fn exec(allocator: &mem.Allocator, argv: []const []const u8, cwd: ?[]const u8,
192 env_map: ?&const BufMap, max_output_size: usize) %ExecResult207 env_map: ?&const BufMap, max_output_size: usize) !ExecResult
193 {208 {
194 const child = try ChildProcess.init(argv, allocator);209 const child = try ChildProcess.init(argv, allocator);
195 defer child.deinit();210 defer child.deinit();
...@@ -220,7 +235,7 @@ pub const ChildProcess = struct {...@@ -220,7 +235,7 @@ pub const ChildProcess = struct {
220 };235 };
221 }236 }
222237
223 fn waitWindows(self: &ChildProcess) %Term {238 fn waitWindows(self: &ChildProcess) !Term {
224 if (self.term) |term| {239 if (self.term) |term| {
225 self.cleanupStreams();240 self.cleanupStreams();
226 return term;241 return term;
...@@ -230,7 +245,7 @@ pub const ChildProcess = struct {...@@ -230,7 +245,7 @@ pub const ChildProcess = struct {
230 return ??self.term;245 return ??self.term;
231 }246 }
232247
233 fn waitPosix(self: &ChildProcess) %Term {248 fn waitPosix(self: &ChildProcess) !Term {
234 block_SIGCHLD();249 block_SIGCHLD();
235 defer restore_SIGCHLD();250 defer restore_SIGCHLD();
236251
...@@ -247,10 +262,10 @@ pub const ChildProcess = struct {...@@ -247,10 +262,10 @@ pub const ChildProcess = struct {
247 self.allocator.destroy(self);262 self.allocator.destroy(self);
248 }263 }
249264
250 fn waitUnwrappedWindows(self: &ChildProcess) %void {265 fn waitUnwrappedWindows(self: &ChildProcess) !void {
251 const result = os.windowsWaitSingle(self.handle, windows.INFINITE);266 const result = os.windowsWaitSingle(self.handle, windows.INFINITE);
252267
253 self.term = (%Term)(x: {268 self.term = (SpawnError!Term)(x: {
254 var exit_code: windows.DWORD = undefined;269 var exit_code: windows.DWORD = undefined;
255 if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {270 if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {
256 break :x Term { .Unknown = 0 };271 break :x Term { .Unknown = 0 };
...@@ -295,7 +310,7 @@ pub const ChildProcess = struct {...@@ -295,7 +310,7 @@ pub const ChildProcess = struct {
295 if (self.stderr) |*stderr| { stderr.close(); self.stderr = null; }310 if (self.stderr) |*stderr| { stderr.close(); self.stderr = null; }
296 }311 }
297312
298 fn cleanupAfterWait(self: &ChildProcess, status: i32) %Term {313 fn cleanupAfterWait(self: &ChildProcess, status: i32) !Term {
299 children_nodes.remove(&self.llnode);314 children_nodes.remove(&self.llnode);
300315
301 defer {316 defer {
...@@ -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);
...@@ -331,7 +346,7 @@ pub const ChildProcess = struct {...@@ -331,7 +346,7 @@ pub const ChildProcess = struct {
331 ;346 ;
332 }347 }
333348
334 fn spawnPosix(self: &ChildProcess) %void {349 fn spawnPosix(self: &ChildProcess) !void {
335 // TODO atomically set a flag saying that we already did this350 // TODO atomically set a flag saying that we already did this
336 install_SIGCHLD_handler();351 install_SIGCHLD_handler();
337352
...@@ -440,7 +455,7 @@ pub const ChildProcess = struct {...@@ -440,7 +455,7 @@ pub const ChildProcess = struct {
440 if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); }455 if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); }
441 }456 }
442457
443 fn spawnWindows(self: &ChildProcess) %void {458 fn spawnWindows(self: &ChildProcess) !void {
444 const saAttr = windows.SECURITY_ATTRIBUTES {459 const saAttr = windows.SECURITY_ATTRIBUTES {
445 .nLength = @sizeOf(windows.SECURITY_ATTRIBUTES),460 .nLength = @sizeOf(windows.SECURITY_ATTRIBUTES),
446 .bInheritHandle = windows.TRUE,461 .bInheritHandle = windows.TRUE,
...@@ -623,7 +638,7 @@ pub const ChildProcess = struct {...@@ -623,7 +638,7 @@ pub const ChildProcess = struct {
623 if (self.stdout_behavior == StdIo.Pipe) { os.close(??g_hChildStd_OUT_Wr); }638 if (self.stdout_behavior == StdIo.Pipe) { os.close(??g_hChildStd_OUT_Wr); }
624 }639 }
625640
626 fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) %void {641 fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) !void {
627 switch (stdio) {642 switch (stdio) {
628 StdIo.Pipe => try os.posixDup2(pipe_fd, std_fileno),643 StdIo.Pipe => try os.posixDup2(pipe_fd, std_fileno),
629 StdIo.Close => os.close(std_fileno),644 StdIo.Close => os.close(std_fileno),
...@@ -635,7 +650,7 @@ pub const ChildProcess = struct {...@@ -635,7 +650,7 @@ pub const ChildProcess = struct {
635};650};
636651
637fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?&u8,652fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?&u8,
638 lpStartupInfo: &windows.STARTUPINFOA, lpProcessInformation: &windows.PROCESS_INFORMATION) %void653 lpStartupInfo: &windows.STARTUPINFOA, lpProcessInformation: &windows.PROCESS_INFORMATION) !void
639{654{
640 if (windows.CreateProcessA(app_name, cmd_line, null, null, windows.TRUE, 0,655 if (windows.CreateProcessA(app_name, cmd_line, null, null, windows.TRUE, 0,
641 @ptrCast(?&c_void, envp_ptr), cwd_ptr, lpStartupInfo, lpProcessInformation) == 0)656 @ptrCast(?&c_void, envp_ptr), cwd_ptr, lpStartupInfo, lpProcessInformation) == 0)
...@@ -655,7 +670,7 @@ fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?...@@ -655,7 +670,7 @@ fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?
655670
656/// Caller must dealloc.671/// Caller must dealloc.
657/// Guarantees a null byte at result[result.len].672/// Guarantees a null byte at result[result.len].
658fn windowsCreateCommandLine(allocator: &mem.Allocator, argv: []const []const u8) %[]u8 {673fn windowsCreateCommandLine(allocator: &mem.Allocator, argv: []const []const u8) ![]u8 {
659 var buf = try Buffer.initSize(allocator, 0);674 var buf = try Buffer.initSize(allocator, 0);
660 defer buf.deinit();675 defer buf.deinit();
661676
...@@ -700,7 +715,7 @@ fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void {...@@ -700,7 +715,7 @@ fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void {
700// a namespace field lookup715// a namespace field lookup
701const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES;716const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES;
702717
703fn windowsMakePipe(rd: &windows.HANDLE, wr: &windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) %void {718fn windowsMakePipe(rd: &windows.HANDLE, wr: &windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) !void {
704 if (windows.CreatePipe(rd, wr, sattr, 0) == 0) {719 if (windows.CreatePipe(rd, wr, sattr, 0) == 0) {
705 const err = windows.GetLastError();720 const err = windows.GetLastError();
706 return switch (err) {721 return switch (err) {
...@@ -709,7 +724,7 @@ fn windowsMakePipe(rd: &windows.HANDLE, wr: &windows.HANDLE, sattr: &const SECUR...@@ -709,7 +724,7 @@ fn windowsMakePipe(rd: &windows.HANDLE, wr: &windows.HANDLE, sattr: &const SECUR
709 }724 }
710}725}
711726
712fn windowsSetHandleInfo(h: windows.HANDLE, mask: windows.DWORD, flags: windows.DWORD) %void {727fn windowsSetHandleInfo(h: windows.HANDLE, mask: windows.DWORD, flags: windows.DWORD) !void {
713 if (windows.SetHandleInformation(h, mask, flags) == 0) {728 if (windows.SetHandleInformation(h, mask, flags) == 0) {
714 const err = windows.GetLastError();729 const err = windows.GetLastError();
715 return switch (err) {730 return switch (err) {
...@@ -718,7 +733,7 @@ fn windowsSetHandleInfo(h: windows.HANDLE, mask: windows.DWORD, flags: windows.D...@@ -718,7 +733,7 @@ fn windowsSetHandleInfo(h: windows.HANDLE, mask: windows.DWORD, flags: windows.D
718 }733 }
719}734}
720735
721fn windowsMakePipeIn(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) %void {736fn windowsMakePipeIn(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) !void {
722 var rd_h: windows.HANDLE = undefined;737 var rd_h: windows.HANDLE = undefined;
723 var wr_h: windows.HANDLE = undefined;738 var wr_h: windows.HANDLE = undefined;
724 try windowsMakePipe(&rd_h, &wr_h, sattr);739 try windowsMakePipe(&rd_h, &wr_h, sattr);
...@@ -728,7 +743,7 @@ fn windowsMakePipeIn(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const S...@@ -728,7 +743,7 @@ fn windowsMakePipeIn(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const S
728 *wr = wr_h;743 *wr = wr_h;
729}744}
730745
731fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) %void {746fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) !void {
732 var rd_h: windows.HANDLE = undefined;747 var rd_h: windows.HANDLE = undefined;
733 var wr_h: windows.HANDLE = undefined;748 var wr_h: windows.HANDLE = undefined;
734 try windowsMakePipe(&rd_h, &wr_h, sattr);749 try windowsMakePipe(&rd_h, &wr_h, sattr);
...@@ -738,7 +753,7 @@ fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const...@@ -738,7 +753,7 @@ fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const
738 *wr = wr_h;753 *wr = wr_h;
739}754}
740755
741fn makePipe() %[2]i32 {756fn makePipe() ![2]i32 {
742 var fds: [2]i32 = undefined;757 var fds: [2]i32 = undefined;
743 const err = posix.getErrno(posix.pipe(&fds));758 const err = posix.getErrno(posix.pipe(&fds));
744 if (err > 0) {759 if (err > 0) {
...@@ -757,20 +772,20 @@ fn destroyPipe(pipe: &const [2]i32) void {...@@ -757,20 +772,20 @@ 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}
764779
765const ErrInt = @IntType(false, @sizeOf(error) * 8);780const ErrInt = @IntType(false, @sizeOf(error) * 8);
766781
767fn writeIntFd(fd: i32, value: ErrInt) %void {782fn writeIntFd(fd: i32, value: ErrInt) !void {
768 var bytes: [@sizeOf(ErrInt)]u8 = undefined;783 var bytes: [@sizeOf(ErrInt)]u8 = undefined;
769 mem.writeInt(bytes[0..], value, builtin.endian);784 mem.writeInt(bytes[0..], value, builtin.endian);
770 os.posixWrite(fd, bytes[0..]) catch return error.SystemResources;785 os.posixWrite(fd, bytes[0..]) catch return error.SystemResources;
771}786}
772787
773fn readIntFd(fd: i32) %ErrInt {788fn readIntFd(fd: i32) !ErrInt {
774 var bytes: [@sizeOf(ErrInt)]u8 = undefined;789 var bytes: [@sizeOf(ErrInt)]u8 = undefined;
775 os.posixRead(fd, bytes[0..]) catch return error.SystemResources;790 os.posixRead(fd, bytes[0..]) catch return error.SystemResources;
776 return mem.readInt(bytes[0..], ErrInt, builtin.endian);791 return mem.readInt(bytes[0..], ErrInt, builtin.endian);
std/os/get_user_id.zig+2-5
...@@ -9,7 +9,7 @@ pub const UserInfo = struct {...@@ -9,7 +9,7 @@ pub const UserInfo = struct {
9};9};
1010
11/// POSIX function which gets a uid from username.11/// POSIX function which gets a uid from username.
12pub fn getUserInfo(name: []const u8) %UserInfo {12pub fn getUserInfo(name: []const u8) !UserInfo {
13 return switch (builtin.os) {13 return switch (builtin.os) {
14 Os.linux, Os.macosx, Os.ios => posixGetUserInfo(name),14 Os.linux, Os.macosx, Os.ios => posixGetUserInfo(name),
15 else => @compileError("Unsupported OS"),15 else => @compileError("Unsupported OS"),
...@@ -24,13 +24,10 @@ const State = enum {...@@ -24,13 +24,10 @@ const State = enum {
24 ReadGroupId,24 ReadGroupId,
25};25};
2626
27error UserNotFound;
28error CorruptPasswordFile;
29
30// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else27// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else
31// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`.28// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`.
3229
33pub fn posixGetUserInfo(name: []const u8) %UserInfo {30pub fn posixGetUserInfo(name: []const u8) !UserInfo {
34 var in_stream = try io.InStream.open("/etc/passwd", null);31 var in_stream = try io.InStream.open("/etc/passwd", null);
35 defer in_stream.close();32 defer in_stream.close();
3633
std/os/index.zig+207-118
...@@ -38,6 +38,10 @@ pub const windowsLoadDll = windows_util.windowsLoadDll;...@@ -38,6 +38,10 @@ pub const windowsLoadDll = windows_util.windowsLoadDll;
38pub const windowsUnloadDll = windows_util.windowsUnloadDll; 38pub const windowsUnloadDll = windows_util.windowsUnloadDll;
39pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;39pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
4040
41pub const WindowsWaitError = windows_util.WaitError;
42pub const WindowsOpenError = windows_util.OpenError;
43pub const WindowsWriteError = windows_util.WriteError;
44
41pub const FileHandle = if (is_windows) windows.HANDLE else i32;45pub const FileHandle = if (is_windows) windows.HANDLE else i32;
4246
43const debug = std.debug;47const debug = std.debug;
...@@ -57,25 +61,10 @@ const ArrayList = std.ArrayList;...@@ -57,25 +61,10 @@ const ArrayList = std.ArrayList;
57const Buffer = std.Buffer;61const Buffer = std.Buffer;
58const math = std.math;62const math = std.math;
5963
60error SystemResources;
61error AccessDenied;
62error InvalidExe;
63error FileSystem;
64error IsDir;
65error FileNotFound;
66error FileBusy;
67error PathAlreadyExists;
68error SymLinkLoop;
69error ReadOnlyFileSystem;
70error LinkQuotaExceeded;
71error RenameAcrossMountPoints;
72error DirNotEmpty;
73error WouldBlock;
74
75/// Fills `buf` with random bytes. If linking against libc, this calls the64/// Fills `buf` with random bytes. If linking against libc, this calls the
76/// appropriate OS-specific library call. Otherwise it uses the zig standard65/// appropriate OS-specific library call. Otherwise it uses the zig standard
77/// library implementation.66/// library implementation.
78pub fn getRandomBytes(buf: []u8) %void {67pub fn getRandomBytes(buf: []u8) !void {
79 switch (builtin.os) {68 switch (builtin.os) {
80 Os.linux => while (true) {69 Os.linux => while (true) {
81 // TODO check libc version and potentially call c.getrandom.70 // TODO check libc version and potentially call c.getrandom.
...@@ -188,7 +177,7 @@ pub fn close(handle: FileHandle) void {...@@ -188,7 +177,7 @@ pub fn close(handle: FileHandle) void {
188}177}
189178
190/// Calls POSIX read, and keeps trying if it gets interrupted.179/// Calls POSIX read, and keeps trying if it gets interrupted.
191pub fn posixRead(fd: i32, buf: []u8) %void {180pub fn posixRead(fd: i32, buf: []u8) !void {
192 // Linux can return EINVAL when read amount is > 0x7ffff000181 // Linux can return EINVAL when read amount is > 0x7ffff000
193 // See https://github.com/zig-lang/zig/pull/743#issuecomment-363158274182 // See https://github.com/zig-lang/zig/pull/743#issuecomment-363158274
194 const max_buf_len = 0x7ffff000;183 const max_buf_len = 0x7ffff000;
...@@ -214,17 +203,21 @@ pub fn posixRead(fd: i32, buf: []u8) %void {...@@ -214,17 +203,21 @@ pub fn posixRead(fd: i32, buf: []u8) %void {
214 }203 }
215}204}
216205
217error WouldBlock;206pub const PosixWriteError = error {
218error FileClosed;207 WouldBlock,
219error DestinationAddressRequired;208 FileClosed,
220error DiskQuota;209 DestinationAddressRequired,
221error FileTooBig;210 DiskQuota,
222error InputOutput;211 FileTooBig,
223error NoSpaceLeft;212 InputOutput,
224error BrokenPipe;213 NoSpaceLeft,
214 AccessDenied,
215 BrokenPipe,
216 Unexpected,
217};
225218
226/// Calls POSIX write, and keeps trying if it gets interrupted.219/// Calls POSIX write, and keeps trying if it gets interrupted.
227pub fn posixWrite(fd: i32, bytes: []const u8) %void {220pub fn posixWrite(fd: i32, bytes: []const u8) !void {
228 // Linux can return EINVAL when write amount is > 0x7ffff000221 // Linux can return EINVAL when write amount is > 0x7ffff000
229 // See https://github.com/zig-lang/zig/pull/743#issuecomment-363165856222 // See https://github.com/zig-lang/zig/pull/743#issuecomment-363165856
230 const max_bytes_len = 0x7ffff000;223 const max_bytes_len = 0x7ffff000;
...@@ -238,15 +231,15 @@ pub fn posixWrite(fd: i32, bytes: []const u8) %void {...@@ -238,15 +231,15 @@ pub fn posixWrite(fd: i32, bytes: []const u8) %void {
238 return switch (write_err) {231 return switch (write_err) {
239 posix.EINTR => continue,232 posix.EINTR => continue,
240 posix.EINVAL, posix.EFAULT => unreachable,233 posix.EINVAL, posix.EFAULT => unreachable,
241 posix.EAGAIN => error.WouldBlock,234 posix.EAGAIN => PosixWriteError.WouldBlock,
242 posix.EBADF => error.FileClosed,235 posix.EBADF => PosixWriteError.FileClosed,
243 posix.EDESTADDRREQ => error.DestinationAddressRequired,236 posix.EDESTADDRREQ => PosixWriteError.DestinationAddressRequired,
244 posix.EDQUOT => error.DiskQuota,237 posix.EDQUOT => PosixWriteError.DiskQuota,
245 posix.EFBIG => error.FileTooBig,238 posix.EFBIG => PosixWriteError.FileTooBig,
246 posix.EIO => error.InputOutput,239 posix.EIO => PosixWriteError.InputOutput,
247 posix.ENOSPC => error.NoSpaceLeft,240 posix.ENOSPC => PosixWriteError.NoSpaceLeft,
248 posix.EPERM => error.AccessDenied,241 posix.EPERM => PosixWriteError.AccessDenied,
249 posix.EPIPE => error.BrokenPipe,242 posix.EPIPE => PosixWriteError.BrokenPipe,
250 else => unexpectedErrorPosix(write_err),243 else => unexpectedErrorPosix(write_err),
251 };244 };
252 }245 }
...@@ -254,13 +247,31 @@ pub fn posixWrite(fd: i32, bytes: []const u8) %void {...@@ -254,13 +247,31 @@ pub fn posixWrite(fd: i32, bytes: []const u8) %void {
254 }247 }
255}248}
256249
250pub const PosixOpenError = error {
251 OutOfMemory,
252 AccessDenied,
253 FileTooBig,
254 IsDir,
255 SymLinkLoop,
256 ProcessFdQuotaExceeded,
257 NameTooLong,
258 SystemFdQuotaExceeded,
259 NoDevice,
260 PathNotFound,
261 SystemResources,
262 NoSpaceLeft,
263 NotDir,
264 PathAlreadyExists,
265 Unexpected,
266};
267
257/// ::file_path may need to be copied in memory to add a null terminating byte. In this case268/// ::file_path may need to be copied in memory to add a null terminating byte. In this case
258/// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed269/// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed
259/// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned.270/// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned.
260/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.271/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
261/// Calls POSIX open, keeps trying if it gets interrupted, and translates272/// Calls POSIX open, keeps trying if it gets interrupted, and translates
262/// the return value into zig errors.273/// the return value into zig errors.
263pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Allocator) %i32 {274pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Allocator) PosixOpenError!i32 {
264 var stack_buf: [max_noalloc_path_len]u8 = undefined;275 var stack_buf: [max_noalloc_path_len]u8 = undefined;
265 var path0: []u8 = undefined;276 var path0: []u8 = undefined;
266 var need_free = false;277 var need_free = false;
...@@ -282,7 +293,7 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al...@@ -282,7 +293,7 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al
282 return posixOpenC(path0.ptr, flags, perm);293 return posixOpenC(path0.ptr, flags, perm);
283}294}
284295
285pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) %i32 {296pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) !i32 {
286 while (true) {297 while (true) {
287 const result = posix.open(file_path, flags, perm);298 const result = posix.open(file_path, flags, perm);
288 const err = posix.getErrno(result);299 const err = posix.getErrno(result);
...@@ -292,20 +303,20 @@ pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) %i32 {...@@ -292,20 +303,20 @@ pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) %i32 {
292303
293 posix.EFAULT => unreachable,304 posix.EFAULT => unreachable,
294 posix.EINVAL => unreachable,305 posix.EINVAL => unreachable,
295 posix.EACCES => error.AccessDenied,306 posix.EACCES => PosixOpenError.AccessDenied,
296 posix.EFBIG, posix.EOVERFLOW => error.FileTooBig,307 posix.EFBIG, posix.EOVERFLOW => PosixOpenError.FileTooBig,
297 posix.EISDIR => error.IsDir,308 posix.EISDIR => PosixOpenError.IsDir,
298 posix.ELOOP => error.SymLinkLoop,309 posix.ELOOP => PosixOpenError.SymLinkLoop,
299 posix.EMFILE => error.ProcessFdQuotaExceeded,310 posix.EMFILE => PosixOpenError.ProcessFdQuotaExceeded,
300 posix.ENAMETOOLONG => error.NameTooLong,311 posix.ENAMETOOLONG => PosixOpenError.NameTooLong,
301 posix.ENFILE => error.SystemFdQuotaExceeded,312 posix.ENFILE => PosixOpenError.SystemFdQuotaExceeded,
302 posix.ENODEV => error.NoDevice,313 posix.ENODEV => PosixOpenError.NoDevice,
303 posix.ENOENT => error.PathNotFound,314 posix.ENOENT => PosixOpenError.PathNotFound,
304 posix.ENOMEM => error.SystemResources,315 posix.ENOMEM => PosixOpenError.SystemResources,
305 posix.ENOSPC => error.NoSpaceLeft,316 posix.ENOSPC => PosixOpenError.NoSpaceLeft,
306 posix.ENOTDIR => error.NotDir,317 posix.ENOTDIR => PosixOpenError.NotDir,
307 posix.EPERM => error.AccessDenied,318 posix.EPERM => PosixOpenError.AccessDenied,
308 posix.EEXIST => error.PathAlreadyExists,319 posix.EEXIST => PosixOpenError.PathAlreadyExists,
309 else => unexpectedErrorPosix(err),320 else => unexpectedErrorPosix(err),
310 };321 };
311 }322 }
...@@ -313,7 +324,7 @@ pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) %i32 {...@@ -313,7 +324,7 @@ pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) %i32 {
313 }324 }
314}325}
315326
316pub fn posixDup2(old_fd: i32, new_fd: i32) %void {327pub fn posixDup2(old_fd: i32, new_fd: i32) !void {
317 while (true) {328 while (true) {
318 const err = posix.getErrno(posix.dup2(old_fd, new_fd));329 const err = posix.getErrno(posix.dup2(old_fd, new_fd));
319 if (err > 0) {330 if (err > 0) {
...@@ -328,7 +339,7 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) %void {...@@ -328,7 +339,7 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) %void {
328 }339 }
329}340}
330341
331pub fn createNullDelimitedEnvMap(allocator: &Allocator, env_map: &const BufMap) %[]?&u8 {342pub fn createNullDelimitedEnvMap(allocator: &Allocator, env_map: &const BufMap) ![]?&u8 {
332 const envp_count = env_map.count();343 const envp_count = env_map.count();
333 const envp_buf = try allocator.alloc(?&u8, envp_count + 1);344 const envp_buf = try allocator.alloc(?&u8, envp_count + 1);
334 mem.set(?&u8, envp_buf, null);345 mem.set(?&u8, envp_buf, null);
...@@ -365,7 +376,7 @@ pub fn freeNullDelimitedEnvMap(allocator: &Allocator, envp_buf: []?&u8) void {...@@ -365,7 +376,7 @@ pub fn freeNullDelimitedEnvMap(allocator: &Allocator, envp_buf: []?&u8) void {
365/// `argv[0]` is the executable path.376/// `argv[0]` is the executable path.
366/// This function also uses the PATH environment variable to get the full path to the executable.377/// This function also uses the PATH environment variable to get the full path to the executable.
367pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,378pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,
368 allocator: &Allocator) %void379 allocator: &Allocator) !void
369{380{
370 const argv_buf = try allocator.alloc(?&u8, argv.len + 1);381 const argv_buf = try allocator.alloc(?&u8, argv.len + 1);
371 mem.set(?&u8, argv_buf, null);382 mem.set(?&u8, argv_buf, null);
...@@ -421,7 +432,19 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,...@@ -421,7 +432,19 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,
421 return posixExecveErrnoToErr(err);432 return posixExecveErrnoToErr(err);
422}433}
423434
424fn posixExecveErrnoToErr(err: usize) error {435pub const PosixExecveError = error {
436 SystemResources,
437 AccessDenied,
438 InvalidExe,
439 FileSystem,
440 IsDir,
441 FileNotFound,
442 NotDir,
443 FileBusy,
444 Unexpected,
445};
446
447fn posixExecveErrnoToErr(err: usize) PosixExecveError {
425 assert(err > 0);448 assert(err > 0);
426 return switch (err) {449 return switch (err) {
427 posix.EFAULT => unreachable,450 posix.EFAULT => unreachable,
...@@ -440,7 +463,7 @@ fn posixExecveErrnoToErr(err: usize) error {...@@ -440,7 +463,7 @@ fn posixExecveErrnoToErr(err: usize) error {
440pub var posix_environ_raw: []&u8 = undefined;463pub var posix_environ_raw: []&u8 = undefined;
441464
442/// Caller must free result when done.465/// Caller must free result when done.
443pub fn getEnvMap(allocator: &Allocator) %BufMap {466pub fn getEnvMap(allocator: &Allocator) !BufMap {
444 var result = BufMap.init(allocator);467 var result = BufMap.init(allocator);
445 errdefer result.deinit();468 errdefer result.deinit();
446469
...@@ -501,10 +524,8 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 {...@@ -501,10 +524,8 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 {
501 return null;524 return null;
502}525}
503526
504error EnvironmentVariableNotFound;
505
506/// Caller must free returned memory.527/// Caller must free returned memory.
507pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) %[]u8 {528pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) ![]u8 {
508 if (is_windows) {529 if (is_windows) {
509 const key_with_null = try cstr.addNullByte(allocator, key);530 const key_with_null = try cstr.addNullByte(allocator, key);
510 defer allocator.free(key_with_null);531 defer allocator.free(key_with_null);
...@@ -538,7 +559,7 @@ pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) %[]u8 {...@@ -538,7 +559,7 @@ pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) %[]u8 {
538}559}
539560
540/// Caller must free the returned memory.561/// Caller must free the returned memory.
541pub fn getCwd(allocator: &Allocator) %[]u8 {562pub fn getCwd(allocator: &Allocator) ![]u8 {
542 switch (builtin.os) {563 switch (builtin.os) {
543 Os.windows => {564 Os.windows => {
544 var buf = try allocator.alloc(u8, 256);565 var buf = try allocator.alloc(u8, 256);
...@@ -585,7 +606,9 @@ test "os.getCwd" {...@@ -585,7 +606,9 @@ test "os.getCwd" {
585 _ = getCwd(debug.global_allocator);606 _ = getCwd(debug.global_allocator);
586}607}
587608
588pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) %void {609pub const SymLinkError = PosixSymLinkError || WindowsSymLinkError;
610
611pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) SymLinkError!void {
589 if (is_windows) {612 if (is_windows) {
590 return symLinkWindows(allocator, existing_path, new_path);613 return symLinkWindows(allocator, existing_path, new_path);
591 } else {614 } else {
...@@ -593,7 +616,12 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con...@@ -593,7 +616,12 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con
593 }616 }
594}617}
595618
596pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) %void {619pub const WindowsSymLinkError = error {
620 OutOfMemory,
621 Unexpected,
622};
623
624pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) WindowsSymLinkError!void {
597 const existing_with_null = try cstr.addNullByte(allocator, existing_path);625 const existing_with_null = try cstr.addNullByte(allocator, existing_path);
598 defer allocator.free(existing_with_null);626 defer allocator.free(existing_with_null);
599 const new_with_null = try cstr.addNullByte(allocator, new_path);627 const new_with_null = try cstr.addNullByte(allocator, new_path);
...@@ -607,7 +635,23 @@ pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path...@@ -607,7 +635,23 @@ pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path
607 }635 }
608}636}
609637
610pub fn symLinkPosix(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) %void {638pub const PosixSymLinkError = error {
639 OutOfMemory,
640 AccessDenied,
641 DiskQuota,
642 PathAlreadyExists,
643 FileSystem,
644 SymLinkLoop,
645 NameTooLong,
646 FileNotFound,
647 SystemResources,
648 NoSpaceLeft,
649 ReadOnlyFileSystem,
650 NotDir,
651 Unexpected,
652};
653
654pub fn symLinkPosix(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) PosixSymLinkError!void {
611 const full_buf = try allocator.alloc(u8, existing_path.len + new_path.len + 2);655 const full_buf = try allocator.alloc(u8, existing_path.len + new_path.len + 2);
612 defer allocator.free(full_buf);656 defer allocator.free(full_buf);
613657
...@@ -644,7 +688,7 @@ const b64_fs_encoder = base64.Base64Encoder.init(...@@ -644,7 +688,7 @@ const b64_fs_encoder = base64.Base64Encoder.init(
644 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",688 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
645 base64.standard_pad_char);689 base64.standard_pad_char);
646690
647pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) %void {691pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) !void {
648 if (symLink(allocator, existing_path, new_path)) {692 if (symLink(allocator, existing_path, new_path)) {
649 return;693 return;
650 } else |err| {694 } else |err| {
...@@ -673,7 +717,7 @@ pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path:...@@ -673,7 +717,7 @@ pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path:
673717
674}718}
675719
676pub fn deleteFile(allocator: &Allocator, file_path: []const u8) %void {720pub fn deleteFile(allocator: &Allocator, file_path: []const u8) !void {
677 if (builtin.os == Os.windows) {721 if (builtin.os == Os.windows) {
678 return deleteFileWindows(allocator, file_path);722 return deleteFileWindows(allocator, file_path);
679 } else {723 } else {
...@@ -681,10 +725,7 @@ pub fn deleteFile(allocator: &Allocator, file_path: []const u8) %void {...@@ -681,10 +725,7 @@ pub fn deleteFile(allocator: &Allocator, file_path: []const u8) %void {
681 }725 }
682}726}
683727
684error FileNotFound;728pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) !void {
685error AccessDenied;
686
687pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) %void {
688 const buf = try allocator.alloc(u8, file_path.len + 1);729 const buf = try allocator.alloc(u8, file_path.len + 1);
689 defer allocator.free(buf);730 defer allocator.free(buf);
690731
...@@ -702,7 +743,7 @@ pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) %void {...@@ -702,7 +743,7 @@ pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) %void {
702 }743 }
703}744}
704745
705pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) %void {746pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) !void {
706 const buf = try allocator.alloc(u8, file_path.len + 1);747 const buf = try allocator.alloc(u8, file_path.len + 1);
707 defer allocator.free(buf);748 defer allocator.free(buf);
708749
...@@ -729,13 +770,13 @@ pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) %void {...@@ -729,13 +770,13 @@ pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) %void {
729}770}
730771
731/// Calls ::copyFileMode with 0o666 for the mode.772/// Calls ::copyFileMode with 0o666 for the mode.
732pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []const u8) %void {773pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []const u8) !void {
733 return copyFileMode(allocator, source_path, dest_path, 0o666);774 return copyFileMode(allocator, source_path, dest_path, 0o666);
734}775}
735776
736// TODO instead of accepting a mode argument, use the mode from fstat'ing the source path once open777// TODO instead of accepting a mode argument, use the mode from fstat'ing the source path once open
737/// Guaranteed to be atomic.778/// Guaranteed to be atomic.
738pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: []const u8, mode: usize) %void {779pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: []const u8, mode: usize) !void {
739 var rand_buf: [12]u8 = undefined;780 var rand_buf: [12]u8 = undefined;
740 const tmp_path = try allocator.alloc(u8, dest_path.len + base64.Base64Encoder.calcSize(rand_buf.len));781 const tmp_path = try allocator.alloc(u8, dest_path.len + base64.Base64Encoder.calcSize(rand_buf.len));
741 defer allocator.free(tmp_path);782 defer allocator.free(tmp_path);
...@@ -759,7 +800,7 @@ pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: [...@@ -759,7 +800,7 @@ pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: [
759 }800 }
760}801}
761802
762pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8) %void {803pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8) !void {
763 const full_buf = try allocator.alloc(u8, old_path.len + new_path.len + 2);804 const full_buf = try allocator.alloc(u8, old_path.len + new_path.len + 2);
764 defer allocator.free(full_buf);805 defer allocator.free(full_buf);
765806
...@@ -804,7 +845,7 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8)...@@ -804,7 +845,7 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8)
804 }845 }
805}846}
806847
807pub fn makeDir(allocator: &Allocator, dir_path: []const u8) %void {848pub fn makeDir(allocator: &Allocator, dir_path: []const u8) !void {
808 if (is_windows) {849 if (is_windows) {
809 return makeDirWindows(allocator, dir_path);850 return makeDirWindows(allocator, dir_path);
810 } else {851 } else {
...@@ -812,7 +853,7 @@ pub fn makeDir(allocator: &Allocator, dir_path: []const u8) %void {...@@ -812,7 +853,7 @@ pub fn makeDir(allocator: &Allocator, dir_path: []const u8) %void {
812 }853 }
813}854}
814855
815pub fn makeDirWindows(allocator: &Allocator, dir_path: []const u8) %void {856pub fn makeDirWindows(allocator: &Allocator, dir_path: []const u8) !void {
816 const path_buf = try cstr.addNullByte(allocator, dir_path);857 const path_buf = try cstr.addNullByte(allocator, dir_path);
817 defer allocator.free(path_buf);858 defer allocator.free(path_buf);
818859
...@@ -826,7 +867,7 @@ pub fn makeDirWindows(allocator: &Allocator, dir_path: []const u8) %void {...@@ -826,7 +867,7 @@ pub fn makeDirWindows(allocator: &Allocator, dir_path: []const u8) %void {
826 }867 }
827}868}
828869
829pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) %void {870pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) !void {
830 const path_buf = try cstr.addNullByte(allocator, dir_path);871 const path_buf = try cstr.addNullByte(allocator, dir_path);
831 defer allocator.free(path_buf);872 defer allocator.free(path_buf);
832873
...@@ -852,7 +893,7 @@ pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) %void {...@@ -852,7 +893,7 @@ pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) %void {
852893
853/// Calls makeDir recursively to make an entire path. Returns success if the path894/// Calls makeDir recursively to make an entire path. Returns success if the path
854/// already exists and is a directory.895/// already exists and is a directory.
855pub fn makePath(allocator: &Allocator, full_path: []const u8) %void {896pub fn makePath(allocator: &Allocator, full_path: []const u8) !void {
856 const resolved_path = try path.resolve(allocator, full_path);897 const resolved_path = try path.resolve(allocator, full_path);
857 defer allocator.free(resolved_path);898 defer allocator.free(resolved_path);
858899
...@@ -890,7 +931,7 @@ pub fn makePath(allocator: &Allocator, full_path: []const u8) %void {...@@ -890,7 +931,7 @@ pub fn makePath(allocator: &Allocator, full_path: []const u8) %void {
890931
891/// Returns ::error.DirNotEmpty if the directory is not empty.932/// Returns ::error.DirNotEmpty if the directory is not empty.
892/// To delete a directory recursively, see ::deleteTree933/// To delete a directory recursively, see ::deleteTree
893pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) %void {934pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) !void {
894 const path_buf = try allocator.alloc(u8, dir_path.len + 1);935 const path_buf = try allocator.alloc(u8, dir_path.len + 1);
895 defer allocator.free(path_buf);936 defer allocator.free(path_buf);
896937
...@@ -919,24 +960,68 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) %void {...@@ -919,24 +960,68 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) %void {
919/// removes it. If it cannot be removed because it is a non-empty directory,960/// removes it. If it cannot be removed because it is a non-empty directory,
920/// this function recursively removes its entries and then tries again.961/// this function recursively removes its entries and then tries again.
921// TODO non-recursive implementation962// TODO non-recursive implementation
922pub fn deleteTree(allocator: &Allocator, full_path: []const u8) %void {963const DeleteTreeError = error {
964 OutOfMemory,
965 AccessDenied,
966 FileTooBig,
967 IsDir,
968 SymLinkLoop,
969 ProcessFdQuotaExceeded,
970 NameTooLong,
971 SystemFdQuotaExceeded,
972 NoDevice,
973 PathNotFound,
974 SystemResources,
975 NoSpaceLeft,
976 PathAlreadyExists,
977 ReadOnlyFileSystem,
978 NotDir,
979 FileNotFound,
980 FileSystem,
981 FileBusy,
982 DirNotEmpty,
983 Unexpected,
984};
985pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!void {
923 start_over: while (true) {986 start_over: while (true) {
924 // First, try deleting the item as a file. This way we don't follow sym links.987 // First, try deleting the item as a file. This way we don't follow sym links.
925 if (deleteFile(allocator, full_path)) {988 if (deleteFile(allocator, full_path)) {
926 return;989 return;
927 } else |err| {990 } else |err| switch (err) {
928 if (err == error.FileNotFound)991 error.FileNotFound => return,
929 return;992 error.IsDir => {},
930 if (err != error.IsDir)993
931 return err;994 error.OutOfMemory,
995 error.AccessDenied,
996 error.SymLinkLoop,
997 error.NameTooLong,
998 error.SystemResources,
999 error.ReadOnlyFileSystem,
1000 error.NotDir,
1001 error.FileSystem,
1002 error.FileBusy,
1003 error.Unexpected
1004 => return err,
932 }1005 }
933 {1006 {
934 var dir = Dir.open(allocator, full_path) catch |err| {1007 var dir = Dir.open(allocator, full_path) catch |err| switch (err) {
935 if (err == error.FileNotFound)1008 error.NotDir => continue :start_over,
936 return;1009
937 if (err == error.NotDir)1010 error.OutOfMemory,
938 continue :start_over;1011 error.AccessDenied,
939 return err;1012 error.FileTooBig,
1013 error.IsDir,
1014 error.SymLinkLoop,
1015 error.ProcessFdQuotaExceeded,
1016 error.NameTooLong,
1017 error.SystemFdQuotaExceeded,
1018 error.NoDevice,
1019 error.PathNotFound,
1020 error.SystemResources,
1021 error.NoSpaceLeft,
1022 error.PathAlreadyExists,
1023 error.Unexpected
1024 => return err,
940 };1025 };
941 defer dir.close();1026 defer dir.close();
9421027
...@@ -988,7 +1073,7 @@ pub const Dir = struct {...@@ -988,7 +1073,7 @@ pub const Dir = struct {
988 };1073 };
989 };1074 };
9901075
991 pub fn open(allocator: &Allocator, dir_path: []const u8) %Dir {1076 pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir {
992 const fd = try posixOpen(dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0, allocator);1077 const fd = try posixOpen(dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0, allocator);
993 return Dir {1078 return Dir {
994 .allocator = allocator,1079 .allocator = allocator,
...@@ -1006,7 +1091,7 @@ pub const Dir = struct {...@@ -1006,7 +1091,7 @@ pub const Dir = struct {
10061091
1007 /// Memory such as file names referenced in this returned entry becomes invalid1092 /// Memory such as file names referenced in this returned entry becomes invalid
1008 /// with subsequent calls to next, as well as when this ::Dir is deinitialized.1093 /// with subsequent calls to next, as well as when this ::Dir is deinitialized.
1009 pub fn next(self: &Dir) %?Entry {1094 pub fn next(self: &Dir) !?Entry {
1010 start_over: while (true) {1095 start_over: while (true) {
1011 if (self.index >= self.end_index) {1096 if (self.index >= self.end_index) {
1012 if (self.buf.len == 0) {1097 if (self.buf.len == 0) {
...@@ -1063,7 +1148,7 @@ pub const Dir = struct {...@@ -1063,7 +1148,7 @@ pub const Dir = struct {
1063 }1148 }
1064};1149};
10651150
1066pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) %void {1151pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) !void {
1067 const path_buf = try allocator.alloc(u8, dir_path.len + 1);1152 const path_buf = try allocator.alloc(u8, dir_path.len + 1);
1068 defer allocator.free(path_buf);1153 defer allocator.free(path_buf);
10691154
...@@ -1087,7 +1172,7 @@ pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) %void {...@@ -1087,7 +1172,7 @@ pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) %void {
1087}1172}
10881173
1089/// Read value of a symbolic link.1174/// Read value of a symbolic link.
1090pub fn readLink(allocator: &Allocator, pathname: []const u8) %[]u8 {1175pub fn readLink(allocator: &Allocator, pathname: []const u8) ![]u8 {
1091 const path_buf = try allocator.alloc(u8, pathname.len + 1);1176 const path_buf = try allocator.alloc(u8, pathname.len + 1);
1092 defer allocator.free(path_buf);1177 defer allocator.free(path_buf);
10931178
...@@ -1164,11 +1249,7 @@ test "os.sleep" {...@@ -1164,11 +1249,7 @@ test "os.sleep" {
1164 sleep(0, 1);1249 sleep(0, 1);
1165}1250}
11661251
1167error ResourceLimitReached;1252pub fn posix_setuid(uid: u32) !void {
1168error InvalidUserId;
1169error PermissionDenied;
1170
1171pub fn posix_setuid(uid: u32) %void {
1172 const err = posix.getErrno(posix.setuid(uid));1253 const err = posix.getErrno(posix.setuid(uid));
1173 if (err == 0) return;1254 if (err == 0) return;
1174 return switch (err) {1255 return switch (err) {
...@@ -1179,7 +1260,7 @@ pub fn posix_setuid(uid: u32) %void {...@@ -1179,7 +1260,7 @@ pub fn posix_setuid(uid: u32) %void {
1179 };1260 };
1180}1261}
11811262
1182pub fn posix_setreuid(ruid: u32, euid: u32) %void {1263pub fn posix_setreuid(ruid: u32, euid: u32) !void {
1183 const err = posix.getErrno(posix.setreuid(ruid, euid));1264 const err = posix.getErrno(posix.setreuid(ruid, euid));
1184 if (err == 0) return;1265 if (err == 0) return;
1185 return switch (err) {1266 return switch (err) {
...@@ -1190,7 +1271,7 @@ pub fn posix_setreuid(ruid: u32, euid: u32) %void {...@@ -1190,7 +1271,7 @@ pub fn posix_setreuid(ruid: u32, euid: u32) %void {
1190 };1271 };
1191}1272}
11921273
1193pub fn posix_setgid(gid: u32) %void {1274pub fn posix_setgid(gid: u32) !void {
1194 const err = posix.getErrno(posix.setgid(gid));1275 const err = posix.getErrno(posix.setgid(gid));
1195 if (err == 0) return;1276 if (err == 0) return;
1196 return switch (err) {1277 return switch (err) {
...@@ -1201,7 +1282,7 @@ pub fn posix_setgid(gid: u32) %void {...@@ -1201,7 +1282,7 @@ pub fn posix_setgid(gid: u32) %void {
1201 };1282 };
1202}1283}
12031284
1204pub fn posix_setregid(rgid: u32, egid: u32) %void {1285pub fn posix_setregid(rgid: u32, egid: u32) !void {
1205 const err = posix.getErrno(posix.setregid(rgid, egid));1286 const err = posix.getErrno(posix.setregid(rgid, egid));
1206 if (err == 0) return;1287 if (err == 0) return;
1207 return switch (err) {1288 return switch (err) {
...@@ -1212,8 +1293,12 @@ pub fn posix_setregid(rgid: u32, egid: u32) %void {...@@ -1212,8 +1293,12 @@ pub fn posix_setregid(rgid: u32, egid: u32) %void {
1212 };1293 };
1213}1294}
12141295
1215error NoStdHandles;1296pub const WindowsGetStdHandleErrs = error {
1216pub fn windowsGetStdHandle(handle_id: windows.DWORD) %windows.HANDLE {1297 NoStdHandles,
1298 Unexpected,
1299};
1300
1301pub fn windowsGetStdHandle(handle_id: windows.DWORD) WindowsGetStdHandleErrs!windows.HANDLE {
1217 if (windows.GetStdHandle(handle_id)) |handle| {1302 if (windows.GetStdHandle(handle_id)) |handle| {
1218 if (handle == windows.INVALID_HANDLE_VALUE) {1303 if (handle == windows.INVALID_HANDLE_VALUE) {
1219 const err = windows.GetLastError();1304 const err = windows.GetLastError();
...@@ -1267,6 +1352,8 @@ pub const ArgIteratorWindows = struct {...@@ -1267,6 +1352,8 @@ pub const ArgIteratorWindows = struct {
1267 quote_count: usize,1352 quote_count: usize,
1268 seen_quote_count: usize,1353 seen_quote_count: usize,
12691354
1355 pub const NextError = error{OutOfMemory};
1356
1270 pub fn init() ArgIteratorWindows {1357 pub fn init() ArgIteratorWindows {
1271 return initWithCmdLine(windows.GetCommandLineA());1358 return initWithCmdLine(windows.GetCommandLineA());
1272 }1359 }
...@@ -1282,7 +1369,7 @@ pub const ArgIteratorWindows = struct {...@@ -1282,7 +1369,7 @@ pub const ArgIteratorWindows = struct {
1282 }1369 }
12831370
1284 /// You must free the returned memory when done.1371 /// You must free the returned memory when done.
1285 pub fn next(self: &ArgIteratorWindows, allocator: &Allocator) ?%[]u8 {1372 pub fn next(self: &ArgIteratorWindows, allocator: &Allocator) ?(NextError![]u8) {
1286 // march forward over whitespace1373 // march forward over whitespace
1287 while (true) : (self.index += 1) {1374 while (true) : (self.index += 1) {
1288 const byte = self.cmd_line[self.index];1375 const byte = self.cmd_line[self.index];
...@@ -1335,7 +1422,7 @@ pub const ArgIteratorWindows = struct {...@@ -1335,7 +1422,7 @@ pub const ArgIteratorWindows = struct {
1335 }1422 }
1336 }1423 }
13371424
1338 fn internalNext(self: &ArgIteratorWindows, allocator: &Allocator) %[]u8 {1425 fn internalNext(self: &ArgIteratorWindows, allocator: &Allocator) NextError![]u8 {
1339 var buf = try Buffer.initSize(allocator, 0);1426 var buf = try Buffer.initSize(allocator, 0);
1340 defer buf.deinit();1427 defer buf.deinit();
13411428
...@@ -1379,7 +1466,7 @@ pub const ArgIteratorWindows = struct {...@@ -1379,7 +1466,7 @@ pub const ArgIteratorWindows = struct {
1379 }1466 }
1380 }1467 }
13811468
1382 fn emitBackslashes(self: &ArgIteratorWindows, buf: &Buffer, emit_count: usize) %void {1469 fn emitBackslashes(self: &ArgIteratorWindows, buf: &Buffer, emit_count: usize) !void {
1383 var i: usize = 0;1470 var i: usize = 0;
1384 while (i < emit_count) : (i += 1) {1471 while (i < emit_count) : (i += 1) {
1385 try buf.appendByte('\\');1472 try buf.appendByte('\\');
...@@ -1409,16 +1496,20 @@ pub const ArgIteratorWindows = struct {...@@ -1409,16 +1496,20 @@ pub const ArgIteratorWindows = struct {
1409};1496};
14101497
1411pub const ArgIterator = struct {1498pub const ArgIterator = struct {
1412 inner: if (builtin.os == Os.windows) ArgIteratorWindows else ArgIteratorPosix,1499 const InnerType = if (builtin.os == Os.windows) ArgIteratorWindows else ArgIteratorPosix;
1500
1501 inner: InnerType,
14131502
1414 pub fn init() ArgIterator {1503 pub fn init() ArgIterator {
1415 return ArgIterator {1504 return ArgIterator {
1416 .inner = if (builtin.os == Os.windows) ArgIteratorWindows.init() else ArgIteratorPosix.init(),1505 .inner = InnerType.init(),
1417 };1506 };
1418 }1507 }
1508
1509 pub const NextError = ArgIteratorWindows.NextError;
1419 1510
1420 /// You must free the returned memory when done.1511 /// You must free the returned memory when done.
1421 pub fn next(self: &ArgIterator, allocator: &Allocator) ?%[]u8 {1512 pub fn next(self: &ArgIterator, allocator: &Allocator) ?(NextError![]u8) {
1422 if (builtin.os == Os.windows) {1513 if (builtin.os == Os.windows) {
1423 return self.inner.next(allocator);1514 return self.inner.next(allocator);
1424 } else {1515 } else {
...@@ -1443,7 +1534,7 @@ pub fn args() ArgIterator {...@@ -1443,7 +1534,7 @@ pub fn args() ArgIterator {
1443}1534}
14441535
1445/// Caller must call freeArgs on result.1536/// Caller must call freeArgs on result.
1446pub fn argsAlloc(allocator: &mem.Allocator) %[]const []u8 {1537pub fn argsAlloc(allocator: &mem.Allocator) ![]const []u8 {
1447 // TODO refactor to only make 1 allocation.1538 // TODO refactor to only make 1 allocation.
1448 var it = args();1539 var it = args();
1449 var contents = try Buffer.initSize(allocator, 0);1540 var contents = try Buffer.initSize(allocator, 0);
...@@ -1525,14 +1616,12 @@ test "std.os" {...@@ -1525,14 +1616,12 @@ test "std.os" {
1525}1616}
15261617
15271618
1528error Unexpected;
1529
1530// TODO make this a build variable that you can set1619// TODO make this a build variable that you can set
1531const unexpected_error_tracing = false;1620const unexpected_error_tracing = false;
15321621
1533/// Call this when you made a syscall or something that sets errno1622/// Call this when you made a syscall or something that sets errno
1534/// and you get an unexpected error.1623/// and you get an unexpected error.
1535pub fn unexpectedErrorPosix(errno: usize) error {1624pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {
1536 if (unexpected_error_tracing) {1625 if (unexpected_error_tracing) {
1537 debug.warn("unexpected errno: {}\n", errno);1626 debug.warn("unexpected errno: {}\n", errno);
1538 debug.dumpStackTrace();1627 debug.dumpStackTrace();
...@@ -1542,7 +1631,7 @@ pub fn unexpectedErrorPosix(errno: usize) error {...@@ -1542,7 +1631,7 @@ pub fn unexpectedErrorPosix(errno: usize) error {
15421631
1543/// Call this when you made a windows DLL call or something that does SetLastError1632/// Call this when you made a windows DLL call or something that does SetLastError
1544/// and you get an unexpected error.1633/// and you get an unexpected error.
1545pub fn unexpectedErrorWindows(err: windows.DWORD) error {1634pub fn unexpectedErrorWindows(err: windows.DWORD) (error{Unexpected}) {
1546 if (unexpected_error_tracing) {1635 if (unexpected_error_tracing) {
1547 debug.warn("unexpected GetLastError(): {}\n", err);1636 debug.warn("unexpected GetLastError(): {}\n", err);
1548 debug.dumpStackTrace();1637 debug.dumpStackTrace();
...@@ -1550,7 +1639,7 @@ pub fn unexpectedErrorWindows(err: windows.DWORD) error {...@@ -1550,7 +1639,7 @@ pub fn unexpectedErrorWindows(err: windows.DWORD) error {
1550 return error.Unexpected;1639 return error.Unexpected;
1551}1640}
15521641
1553pub fn openSelfExe() %io.File {1642pub fn openSelfExe() !io.File {
1554 switch (builtin.os) {1643 switch (builtin.os) {
1555 Os.linux => {1644 Os.linux => {
1556 return io.File.openRead("/proc/self/exe", null);1645 return io.File.openRead("/proc/self/exe", null);
...@@ -1578,7 +1667,7 @@ test "openSelfExe" {...@@ -1578,7 +1667,7 @@ test "openSelfExe" {
1578/// This function may return an error if the current executable1667/// This function may return an error if the current executable
1579/// was deleted after spawning.1668/// was deleted after spawning.
1580/// Caller owns returned memory.1669/// Caller owns returned memory.
1581pub fn selfExePath(allocator: &mem.Allocator) %[]u8 {1670pub fn selfExePath(allocator: &mem.Allocator) ![]u8 {
1582 switch (builtin.os) {1671 switch (builtin.os) {
1583 Os.linux => {1672 Os.linux => {
1584 // If the currently executing binary has been deleted,1673 // If the currently executing binary has been deleted,
...@@ -1621,7 +1710,7 @@ pub fn selfExePath(allocator: &mem.Allocator) %[]u8 {...@@ -1621,7 +1710,7 @@ pub fn selfExePath(allocator: &mem.Allocator) %[]u8 {
16211710
1622/// Get the directory path that contains the current executable.1711/// Get the directory path that contains the current executable.
1623/// Caller owns returned memory.1712/// Caller owns returned memory.
1624pub fn selfExeDirPath(allocator: &mem.Allocator) %[]u8 {1713pub fn selfExeDirPath(allocator: &mem.Allocator) ![]u8 {
1625 switch (builtin.os) {1714 switch (builtin.os) {
1626 Os.linux => {1715 Os.linux => {
1627 // If the currently executing binary has been deleted,1716 // If the currently executing binary has been deleted,
std/os/linux/index.zig+1-1
...@@ -720,7 +720,7 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags:...@@ -720,7 +720,7 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags:
720// error SystemResources;720// error SystemResources;
721// error Io;721// error Io;
722// 722//
723// pub fn if_nametoindex(name: []u8) %u32 {723// pub fn if_nametoindex(name: []u8) !u32 {
724// var ifr: ifreq = undefined;724// var ifr: ifreq = undefined;
725// 725//
726// if (name.len >= ifr.ifr_name.len) {726// if (name.len >= ifr.ifr_name.len) {
std/os/path.zig+11-18
...@@ -32,7 +32,7 @@ pub fn isSep(byte: u8) bool {...@@ -32,7 +32,7 @@ pub fn isSep(byte: u8) bool {
3232
33/// Naively combines a series of paths with the native path seperator.33/// Naively combines a series of paths with the native path seperator.
34/// Allocates memory for the result, which must be freed by the caller.34/// Allocates memory for the result, which must be freed by the caller.
35pub fn join(allocator: &Allocator, paths: ...) %[]u8 {35pub fn join(allocator: &Allocator, paths: ...) ![]u8 {
36 if (is_windows) {36 if (is_windows) {
37 return joinWindows(allocator, paths);37 return joinWindows(allocator, paths);
38 } else {38 } else {
...@@ -40,11 +40,11 @@ pub fn join(allocator: &Allocator, paths: ...) %[]u8 {...@@ -40,11 +40,11 @@ pub fn join(allocator: &Allocator, paths: ...) %[]u8 {
40 }40 }
41}41}
4242
43pub fn joinWindows(allocator: &Allocator, paths: ...) %[]u8 {43pub fn joinWindows(allocator: &Allocator, paths: ...) ![]u8 {
44 return mem.join(allocator, sep_windows, paths);44 return mem.join(allocator, sep_windows, paths);
45}45}
4646
47pub fn joinPosix(allocator: &Allocator, paths: ...) %[]u8 {47pub fn joinPosix(allocator: &Allocator, paths: ...) ![]u8 {
48 return mem.join(allocator, sep_posix, paths);48 return mem.join(allocator, sep_posix, paths);
49}49}
5050
...@@ -313,7 +313,7 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool {...@@ -313,7 +313,7 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool {
313}313}
314314
315/// Converts the command line arguments into a slice and calls `resolveSlice`.315/// Converts the command line arguments into a slice and calls `resolveSlice`.
316pub fn resolve(allocator: &Allocator, args: ...) %[]u8 {316pub fn resolve(allocator: &Allocator, args: ...) ![]u8 {
317 var paths: [args.len][]const u8 = undefined;317 var paths: [args.len][]const u8 = undefined;
318 comptime var arg_i = 0;318 comptime var arg_i = 0;
319 inline while (arg_i < args.len) : (arg_i += 1) {319 inline while (arg_i < args.len) : (arg_i += 1) {
...@@ -323,7 +323,7 @@ pub fn resolve(allocator: &Allocator, args: ...) %[]u8 {...@@ -323,7 +323,7 @@ pub fn resolve(allocator: &Allocator, args: ...) %[]u8 {
323}323}
324324
325/// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`.325/// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`.
326pub fn resolveSlice(allocator: &Allocator, paths: []const []const u8) %[]u8 {326pub fn resolveSlice(allocator: &Allocator, paths: []const []const u8) ![]u8 {
327 if (is_windows) {327 if (is_windows) {
328 return resolveWindows(allocator, paths);328 return resolveWindows(allocator, paths);
329 } else {329 } else {
...@@ -337,7 +337,7 @@ pub fn resolveSlice(allocator: &Allocator, paths: []const []const u8) %[]u8 {...@@ -337,7 +337,7 @@ pub fn resolveSlice(allocator: &Allocator, paths: []const []const u8) %[]u8 {
337/// If all paths are relative it uses the current working directory as a starting point.337/// If all paths are relative it uses the current working directory as a starting point.
338/// Each drive has its own current working directory.338/// Each drive has its own current working directory.
339/// Path separators are canonicalized to '\\' and drives are canonicalized to capital letters.339/// Path separators are canonicalized to '\\' and drives are canonicalized to capital letters.
340pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) %[]u8 {340pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) ![]u8 {
341 if (paths.len == 0) {341 if (paths.len == 0) {
342 assert(is_windows); // resolveWindows called on non windows can't use getCwd342 assert(is_windows); // resolveWindows called on non windows can't use getCwd
343 return os.getCwd(allocator);343 return os.getCwd(allocator);
...@@ -520,7 +520,7 @@ pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) %[]u8 {...@@ -520,7 +520,7 @@ pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) %[]u8 {
520/// It resolves "." and "..".520/// It resolves "." and "..".
521/// The result does not have a trailing path separator.521/// The result does not have a trailing path separator.
522/// If all paths are relative it uses the current working directory as a starting point.522/// If all paths are relative it uses the current working directory as a starting point.
523pub fn resolvePosix(allocator: &Allocator, paths: []const []const u8) %[]u8 {523pub fn resolvePosix(allocator: &Allocator, paths: []const []const u8) ![]u8 {
524 if (paths.len == 0) {524 if (paths.len == 0) {
525 assert(!is_windows); // resolvePosix called on windows can't use getCwd525 assert(!is_windows); // resolvePosix called on windows can't use getCwd
526 return os.getCwd(allocator);526 return os.getCwd(allocator);
...@@ -890,7 +890,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) void {...@@ -890,7 +890,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) void {
890/// resolve to the same path (after calling `resolve` on each), a zero-length890/// resolve to the same path (after calling `resolve` on each), a zero-length
891/// string is returned.891/// string is returned.
892/// On Windows this canonicalizes the drive to a capital letter and paths to `\\`.892/// On Windows this canonicalizes the drive to a capital letter and paths to `\\`.
893pub fn relative(allocator: &Allocator, from: []const u8, to: []const u8) %[]u8 {893pub fn relative(allocator: &Allocator, from: []const u8, to: []const u8) ![]u8 {
894 if (is_windows) {894 if (is_windows) {
895 return relativeWindows(allocator, from, to);895 return relativeWindows(allocator, from, to);
896 } else {896 } else {
...@@ -898,7 +898,7 @@ pub fn relative(allocator: &Allocator, from: []const u8, to: []const u8) %[]u8 {...@@ -898,7 +898,7 @@ pub fn relative(allocator: &Allocator, from: []const u8, to: []const u8) %[]u8 {
898 }898 }
899}899}
900900
901pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8) %[]u8 {901pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8) ![]u8 {
902 const resolved_from = try resolveWindows(allocator, [][]const u8{from});902 const resolved_from = try resolveWindows(allocator, [][]const u8{from});
903 defer allocator.free(resolved_from);903 defer allocator.free(resolved_from);
904904
...@@ -971,7 +971,7 @@ pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8)...@@ -971,7 +971,7 @@ pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8)
971 return []u8{};971 return []u8{};
972}972}
973973
974pub fn relativePosix(allocator: &Allocator, from: []const u8, to: []const u8) %[]u8 {974pub fn relativePosix(allocator: &Allocator, from: []const u8, to: []const u8) ![]u8 {
975 const resolved_from = try resolvePosix(allocator, [][]const u8{from});975 const resolved_from = try resolvePosix(allocator, [][]const u8{from});
976 defer allocator.free(resolved_from);976 defer allocator.free(resolved_from);
977977
...@@ -1066,18 +1066,11 @@ fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []cons...@@ -1066,18 +1066,11 @@ fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []cons
1066 assert(mem.eql(u8, result, expected_output));1066 assert(mem.eql(u8, result, expected_output));
1067}1067}
10681068
1069error AccessDenied;
1070error FileNotFound;
1071error NotSupported;
1072error NotDir;
1073error NameTooLong;
1074error SymLinkLoop;
1075error InputOutput;
1076/// Return the canonicalized absolute pathname.1069/// Return the canonicalized absolute pathname.
1077/// Expands all symbolic links and resolves references to `.`, `..`, and1070/// Expands all symbolic links and resolves references to `.`, `..`, and
1078/// extra `/` characters in ::pathname.1071/// extra `/` characters in ::pathname.
1079/// Caller must deallocate result.1072/// Caller must deallocate result.
1080pub fn real(allocator: &Allocator, pathname: []const u8) %[]u8 {1073pub fn real(allocator: &Allocator, pathname: []const u8) ![]u8 {
1081 switch (builtin.os) {1074 switch (builtin.os) {
1082 Os.windows => {1075 Os.windows => {
1083 const pathname_buf = try allocator.alloc(u8, pathname.len + 1);1076 const pathname_buf = try allocator.alloc(u8, pathname.len + 1);
std/os/windows/util.zig+42-26
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("../../index.zig");1const std = @import("../../index.zig");
2const builtin = @import("builtin");
2const os = std.os;3const os = std.os;
3const windows = std.os.windows;4const windows = std.os.windows;
4const assert = std.debug.assert;5const assert = std.debug.assert;
...@@ -6,11 +7,13 @@ const mem = std.mem;...@@ -6,11 +7,13 @@ const mem = std.mem;
6const BufMap = std.BufMap;7const BufMap = std.BufMap;
7const cstr = std.cstr;8const cstr = std.cstr;
89
9error WaitAbandoned;10pub const WaitError = error {
10error WaitTimeOut;11 WaitAbandoned,
11error Unexpected;12 WaitTimeOut,
13 Unexpected,
14};
1215
13pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) %void {16pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) WaitError!void {
14 const result = windows.WaitForSingleObject(handle, milliseconds);17 const result = windows.WaitForSingleObject(handle, milliseconds);
15 return switch (result) {18 return switch (result) {
16 windows.WAIT_ABANDONED => error.WaitAbandoned,19 windows.WAIT_ABANDONED => error.WaitAbandoned,
...@@ -30,21 +33,24 @@ pub fn windowsClose(handle: windows.HANDLE) void {...@@ -30,21 +33,24 @@ pub fn windowsClose(handle: windows.HANDLE) void {
30 assert(windows.CloseHandle(handle) != 0);33 assert(windows.CloseHandle(handle) != 0);
31}34}
3235
33error SystemResources;36pub const WriteError = error {
34error OperationAborted;37 SystemResources,
35error IoPending;38 OperationAborted,
36error BrokenPipe;39 IoPending,
40 BrokenPipe,
41 Unexpected,
42};
3743
38pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) %void {44pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) WriteError!void {
39 if (windows.WriteFile(handle, @ptrCast(&const c_void, bytes.ptr), u32(bytes.len), null, null) == 0) {45 if (windows.WriteFile(handle, @ptrCast(&const c_void, bytes.ptr), u32(bytes.len), null, null) == 0) {
40 const err = windows.GetLastError();46 const err = windows.GetLastError();
41 return switch (err) {47 return switch (err) {
42 windows.ERROR.INVALID_USER_BUFFER => error.SystemResources,48 windows.ERROR.INVALID_USER_BUFFER => WriteError.SystemResources,
43 windows.ERROR.NOT_ENOUGH_MEMORY => error.SystemResources,49 windows.ERROR.NOT_ENOUGH_MEMORY => WriteError.SystemResources,
44 windows.ERROR.OPERATION_ABORTED => error.OperationAborted,50 windows.ERROR.OPERATION_ABORTED => WriteError.OperationAborted,
45 windows.ERROR.NOT_ENOUGH_QUOTA => error.SystemResources,51 windows.ERROR.NOT_ENOUGH_QUOTA => WriteError.SystemResources,
46 windows.ERROR.IO_PENDING => error.IoPending,52 windows.ERROR.IO_PENDING => WriteError.IoPending,
47 windows.ERROR.BROKEN_PIPE => error.BrokenPipe,53 windows.ERROR.BROKEN_PIPE => WriteError.BrokenPipe,
48 else => os.unexpectedErrorWindows(err),54 else => os.unexpectedErrorWindows(err),
49 };55 };
50 }56 }
...@@ -75,15 +81,24 @@ pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool {...@@ -75,15 +81,24 @@ pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool {
75 mem.indexOf(u16, name_wide, []u16{'-','p','t','y'}) != null;81 mem.indexOf(u16, name_wide, []u16{'-','p','t','y'}) != null;
76}82}
7783
78error SharingViolation;84pub const OpenError = error {
79error PipeBusy;85 SharingViolation,
86 PathAlreadyExists,
87 FileNotFound,
88 AccessDenied,
89 PipeBusy,
90 Unexpected,
91 OutOfMemory,
92 NameTooLong,
93};
8094
81/// `file_path` may need to be copied in memory to add a null terminating byte. In this case95/// `file_path` may need to be copied in memory to add a null terminating byte. In this case
82/// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed96/// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed
83/// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned.97/// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned.
84/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.98/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
85pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_mode: windows.DWORD,99pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_mode: windows.DWORD,
86 creation_disposition: windows.DWORD, flags_and_attrs: windows.DWORD, allocator: ?&mem.Allocator) %windows.HANDLE100 creation_disposition: windows.DWORD, flags_and_attrs: windows.DWORD, allocator: ?&mem.Allocator)
101 OpenError!windows.HANDLE
87{102{
88 var stack_buf: [os.max_noalloc_path_len]u8 = undefined;103 var stack_buf: [os.max_noalloc_path_len]u8 = undefined;
89 var path0: []u8 = undefined;104 var path0: []u8 = undefined;
...@@ -107,11 +122,11 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m...@@ -107,11 +122,11 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m
107 if (result == windows.INVALID_HANDLE_VALUE) {122 if (result == windows.INVALID_HANDLE_VALUE) {
108 const err = windows.GetLastError();123 const err = windows.GetLastError();
109 return switch (err) {124 return switch (err) {
110 windows.ERROR.SHARING_VIOLATION => error.SharingViolation,125 windows.ERROR.SHARING_VIOLATION => OpenError.SharingViolation,
111 windows.ERROR.ALREADY_EXISTS, windows.ERROR.FILE_EXISTS => error.PathAlreadyExists,126 windows.ERROR.ALREADY_EXISTS, windows.ERROR.FILE_EXISTS => OpenError.PathAlreadyExists,
112 windows.ERROR.FILE_NOT_FOUND => error.FileNotFound,127 windows.ERROR.FILE_NOT_FOUND => OpenError.FileNotFound,
113 windows.ERROR.ACCESS_DENIED => error.AccessDenied,128 windows.ERROR.ACCESS_DENIED => OpenError.AccessDenied,
114 windows.ERROR.PIPE_BUSY => error.PipeBusy,129 windows.ERROR.PIPE_BUSY => OpenError.PipeBusy,
115 else => os.unexpectedErrorWindows(err),130 else => os.unexpectedErrorWindows(err),
116 };131 };
117 }132 }
...@@ -120,7 +135,7 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m...@@ -120,7 +135,7 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m
120}135}
121136
122/// Caller must free result.137/// Caller must free result.
123pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) %[]u8 {138pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) ![]u8 {
124 // count bytes needed139 // count bytes needed
125 const bytes_needed = x: {140 const bytes_needed = x: {
126 var bytes_needed: usize = 1; // 1 for the final null byte141 var bytes_needed: usize = 1; // 1 for the final null byte
...@@ -151,8 +166,7 @@ pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap)...@@ -151,8 +166,7 @@ pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap)
151 return result;166 return result;
152}167}
153168
154error DllNotFound;169pub fn windowsLoadDll(allocator: &mem.Allocator, dll_path: []const u8) !windows.HMODULE {
155pub fn windowsLoadDll(allocator: &mem.Allocator, dll_path: []const u8) %windows.HMODULE {
156 const padded_buff = try cstr.addNullByte(allocator, dll_path);170 const padded_buff = try cstr.addNullByte(allocator, dll_path);
157 defer allocator.free(padded_buff);171 defer allocator.free(padded_buff);
158 return windows.LoadLibraryA(padded_buff.ptr) ?? error.DllNotFound;172 return windows.LoadLibraryA(padded_buff.ptr) ?? error.DllNotFound;
...@@ -164,6 +178,8 @@ pub fn windowsUnloadDll(hModule: windows.HMODULE) void {...@@ -164,6 +178,8 @@ pub fn windowsUnloadDll(hModule: windows.HMODULE) void {
164178
165179
166test "InvalidDll" {180test "InvalidDll" {
181 if (builtin.os != builtin.Os.windows) return;
182
167 const DllName = "asdf.dll";183 const DllName = "asdf.dll";
168 const allocator = std.debug.global_allocator;184 const allocator = std.debug.global_allocator;
169 const handle = os.windowsLoadDll(allocator, DllName) catch |err| {185 const handle = os.windowsLoadDll(allocator, DllName) catch |err| {
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_file_template.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 mode = b.standardReleaseOptions();4 const mode = b.standardReleaseOptions();
5 const exe = b.addExecutable("YOUR_NAME_HERE", "src/main.zig");5 const exe = b.addExecutable("YOUR_NAME_HERE", "src/main.zig");
6 exe.setBuildMode(mode);6 exe.setBuildMode(mode);
std/special/build_runner.zig+19-10
...@@ -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;
...@@ -8,9 +9,7 @@ const mem = std.mem;...@@ -8,9 +9,7 @@ const mem = std.mem;
8const ArrayList = std.ArrayList;9const ArrayList = std.ArrayList;
9const warn = std.debug.warn;10const warn = std.debug.warn;
1011
11error InvalidArgs;12pub fn main() !void {
12
13pub fn main() %void {
14 var arg_it = os.args();13 var arg_it = os.args();
1514
16 // TODO use a more general purpose allocator here15 // TODO use a more general purpose allocator here
...@@ -45,14 +44,14 @@ pub fn main() %void {...@@ -45,14 +44,14 @@ pub fn main() %void {
4544
46 var stderr_file = io.getStdErr();45 var stderr_file = io.getStdErr();
47 var stderr_file_stream: io.FileOutStream = undefined;46 var stderr_file_stream: io.FileOutStream = undefined;
48 var stderr_stream: %&io.OutStream = if (stderr_file) |*f| x: {47 var stderr_stream = if (stderr_file) |*f| x: {
49 stderr_file_stream = io.FileOutStream.init(f);48 stderr_file_stream = io.FileOutStream.init(f);
50 break :x &stderr_file_stream.stream;49 break :x &stderr_file_stream.stream;
51 } else |err| err;50 } else |err| err;
5251
53 var stdout_file = io.getStdOut();52 var stdout_file = io.getStdOut();
54 var stdout_file_stream: io.FileOutStream = undefined;53 var stdout_file_stream: io.FileOutStream = undefined;
55 var stdout_stream: %&io.OutStream = if (stdout_file) |*f| x: {54 var stdout_stream = if (stdout_file) |*f| x: {
56 stdout_file_stream = io.FileOutStream.init(f);55 stdout_file_stream = io.FileOutStream.init(f);
57 break :x &stdout_file_stream.stream;56 break :x &stdout_file_stream.stream;
58 } else |err| err;57 } else |err| err;
...@@ -112,7 +111,7 @@ pub fn main() %void {...@@ -112,7 +111,7 @@ pub fn main() %void {
112 }111 }
113112
114 builder.setInstallPrefix(prefix);113 builder.setInstallPrefix(prefix);
115 try root.build(&builder);114 try runBuild(&builder);
116115
117 if (builder.validateUserInputDidItFail())116 if (builder.validateUserInputDidItFail())
118 return usageAndErr(&builder, true, try stderr_stream);117 return usageAndErr(&builder, true, try stderr_stream);
...@@ -125,11 +124,19 @@ pub fn main() %void {...@@ -125,11 +124,19 @@ pub fn main() %void {
125 };124 };
126}125}
127126
128fn 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 {
129 // run the build script to collect the options136 // run the build script to collect the options
130 if (!already_ran_build) {137 if (!already_ran_build) {
131 builder.setInstallPrefix(null);138 builder.setInstallPrefix(null);
132 try root.build(builder);139 try runBuild(builder);
133 }140 }
134141
135 // This usage text has to be synchronized with src/main.cpp142 // This usage text has to be synchronized with src/main.cpp
...@@ -184,12 +191,14 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)...@@ -184,12 +191,14 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)
184 );191 );
185}192}
186193
187fn usageAndErr(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) error {194fn usageAndErr(builder: &Builder, already_ran_build: bool, out_stream: var) error {
188 usage(builder, already_ran_build, out_stream) catch {};195 usage(builder, already_ran_build, out_stream) catch {};
189 return error.InvalidArgs;196 return error.InvalidArgs;
190}197}
191198
192fn unwrapArg(arg: %[]u8) %[]u8 {199const UnwrapArgError = error {OutOfMemory};
200
201fn unwrapArg(arg: UnwrapArgError![]u8) UnwrapArgError![]u8 {
193 return arg catch |err| {202 return arg catch |err| {
194 warn("Unable to parse command line: {}\n", err);203 warn("Unable to parse command line: {}\n", err);
195 return err;204 return err;
std/special/test_runner.zig+1-1
...@@ -4,7 +4,7 @@ const builtin = @import("builtin");...@@ -4,7 +4,7 @@ const builtin = @import("builtin");
4const test_fn_list = builtin.__zig_test_fn_slice;4const test_fn_list = builtin.__zig_test_fn_slice;
5const warn = std.debug.warn;5const warn = std.debug.warn;
66
7pub fn main() %void {7pub fn main() !void {
8 for (test_fn_list) |test_fn, i| {8 for (test_fn_list) |test_fn, i| {
9 warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name);9 warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name);
1010
std/unicode.zig+6-14
...@@ -1,11 +1,9 @@...@@ -1,11 +1,9 @@
1const std = @import("./index.zig");1const std = @import("./index.zig");
22
3error Utf8InvalidStartByte;
4
5/// Given the first byte of a UTF-8 codepoint,3/// Given the first byte of a UTF-8 codepoint,
6/// returns a number 1-4 indicating the total length of the codepoint in bytes.4/// returns a number 1-4 indicating the total length of the codepoint in bytes.
7/// If this byte does not match the form of a UTF-8 start byte, returns Utf8InvalidStartByte.5/// If this byte does not match the form of a UTF-8 start byte, returns Utf8InvalidStartByte.
8pub fn utf8ByteSequenceLength(first_byte: u8) %u3 {6pub fn utf8ByteSequenceLength(first_byte: u8) !u3 {
9 if (first_byte < 0b10000000) return u3(1);7 if (first_byte < 0b10000000) return u3(1);
10 if (first_byte & 0b11100000 == 0b11000000) return u3(2);8 if (first_byte & 0b11100000 == 0b11000000) return u3(2);
11 if (first_byte & 0b11110000 == 0b11100000) return u3(3);9 if (first_byte & 0b11110000 == 0b11100000) return u3(3);
...@@ -13,16 +11,11 @@ pub fn utf8ByteSequenceLength(first_byte: u8) %u3 {...@@ -13,16 +11,11 @@ pub fn utf8ByteSequenceLength(first_byte: u8) %u3 {
13 return error.Utf8InvalidStartByte;11 return error.Utf8InvalidStartByte;
14}12}
1513
16error Utf8OverlongEncoding;
17error Utf8ExpectedContinuation;
18error Utf8EncodesSurrogateHalf;
19error Utf8CodepointTooLarge;
20
21/// Decodes the UTF-8 codepoint encoded in the given slice of bytes.14/// Decodes the UTF-8 codepoint encoded in the given slice of bytes.
22/// bytes.len must be equal to utf8ByteSequenceLength(bytes[0]) catch unreachable.15/// bytes.len must be equal to utf8ByteSequenceLength(bytes[0]) catch unreachable.
23/// If you already know the length at comptime, you can call one of16/// If you already know the length at comptime, you can call one of
24/// utf8Decode2,utf8Decode3,utf8Decode4 directly instead of this function.17/// utf8Decode2,utf8Decode3,utf8Decode4 directly instead of this function.
25pub fn utf8Decode(bytes: []const u8) %u32 {18pub fn utf8Decode(bytes: []const u8) !u32 {
26 return switch (bytes.len) {19 return switch (bytes.len) {
27 1 => u32(bytes[0]),20 1 => u32(bytes[0]),
28 2 => utf8Decode2(bytes),21 2 => utf8Decode2(bytes),
...@@ -31,7 +24,7 @@ pub fn utf8Decode(bytes: []const u8) %u32 {...@@ -31,7 +24,7 @@ pub fn utf8Decode(bytes: []const u8) %u32 {
31 else => unreachable,24 else => unreachable,
32 };25 };
33}26}
34pub fn utf8Decode2(bytes: []const u8) %u32 {27pub fn utf8Decode2(bytes: []const u8) !u32 {
35 std.debug.assert(bytes.len == 2);28 std.debug.assert(bytes.len == 2);
36 std.debug.assert(bytes[0] & 0b11100000 == 0b11000000);29 std.debug.assert(bytes[0] & 0b11100000 == 0b11000000);
37 var value: u32 = bytes[0] & 0b00011111;30 var value: u32 = bytes[0] & 0b00011111;
...@@ -44,7 +37,7 @@ pub fn utf8Decode2(bytes: []const u8) %u32 {...@@ -44,7 +37,7 @@ pub fn utf8Decode2(bytes: []const u8) %u32 {
4437
45 return value;38 return value;
46}39}
47pub fn utf8Decode3(bytes: []const u8) %u32 {40pub fn utf8Decode3(bytes: []const u8) !u32 {
48 std.debug.assert(bytes.len == 3);41 std.debug.assert(bytes.len == 3);
49 std.debug.assert(bytes[0] & 0b11110000 == 0b11100000);42 std.debug.assert(bytes[0] & 0b11110000 == 0b11100000);
50 var value: u32 = bytes[0] & 0b00001111;43 var value: u32 = bytes[0] & 0b00001111;
...@@ -62,7 +55,7 @@ pub fn utf8Decode3(bytes: []const u8) %u32 {...@@ -62,7 +55,7 @@ pub fn utf8Decode3(bytes: []const u8) %u32 {
6255
63 return value;56 return value;
64}57}
65pub fn utf8Decode4(bytes: []const u8) %u32 {58pub fn utf8Decode4(bytes: []const u8) !u32 {
66 std.debug.assert(bytes.len == 4);59 std.debug.assert(bytes.len == 4);
67 std.debug.assert(bytes[0] & 0b11111000 == 0b11110000);60 std.debug.assert(bytes[0] & 0b11111000 == 0b11110000);
68 var value: u32 = bytes[0] & 0b00000111;61 var value: u32 = bytes[0] & 0b00000111;
...@@ -85,7 +78,6 @@ pub fn utf8Decode4(bytes: []const u8) %u32 {...@@ -85,7 +78,6 @@ pub fn utf8Decode4(bytes: []const u8) %u32 {
85 return value;78 return value;
86}79}
8780
88error UnexpectedEof;
89test "valid utf8" {81test "valid utf8" {
90 testValid("\x00", 0x0);82 testValid("\x00", 0x0);
91 testValid("\x20", 0x20);83 testValid("\x20", 0x20);
...@@ -161,7 +153,7 @@ fn testValid(bytes: []const u8, expected_codepoint: u32) void {...@@ -161,7 +153,7 @@ fn testValid(bytes: []const u8, expected_codepoint: u32) void {
161 std.debug.assert((testDecode(bytes) catch unreachable) == expected_codepoint);153 std.debug.assert((testDecode(bytes) catch unreachable) == expected_codepoint);
162}154}
163155
164fn testDecode(bytes: []const u8) %u32 {156fn testDecode(bytes: []const u8) !u32 {
165 const length = try utf8ByteSequenceLength(bytes[0]);157 const length = try utf8ByteSequenceLength(bytes[0]);
166 if (bytes.len < length) return error.UnexpectedEof;158 if (bytes.len < length) return error.UnexpectedEof;
167 std.debug.assert(bytes.len == length);159 std.debug.assert(bytes.len == length);
test/cases/cast.zig+16-18
...@@ -32,7 +32,6 @@ fn funcWithConstPtrPtr(x: &const &i32) void {...@@ -32,7 +32,6 @@ fn funcWithConstPtrPtr(x: &const &i32) void {
32 **x += 1;32 **x += 1;
33}33}
3434
35error ItBroke;
36test "explicit cast from integer to error type" {35test "explicit cast from integer to error type" {
37 testCastIntToErr(error.ItBroke);36 testCastIntToErr(error.ItBroke);
38 comptime testCastIntToErr(error.ItBroke);37 comptime testCastIntToErr(error.ItBroke);
...@@ -75,7 +74,7 @@ test "string literal to &const []const u8" {...@@ -75,7 +74,7 @@ test "string literal to &const []const u8" {
75 assert(mem.eql(u8, *x, "hello"));74 assert(mem.eql(u8, *x, "hello"));
76}75}
7776
78test "implicitly cast from T to %?T" {77test "implicitly cast from T to error!?T" {
79 castToMaybeTypeError(1);78 castToMaybeTypeError(1);
80 comptime castToMaybeTypeError(1);79 comptime castToMaybeTypeError(1);
81}80}
...@@ -84,37 +83,37 @@ const A = struct {...@@ -84,37 +83,37 @@ const A = struct {
84};83};
85fn castToMaybeTypeError(z: i32) void {84fn castToMaybeTypeError(z: i32) void {
86 const x = i32(1);85 const x = i32(1);
87 const y: %?i32 = x;86 const y: error!?i32 = x;
88 assert(??(try y) == 1);87 assert(??(try y) == 1);
8988
90 const f = z;89 const f = z;
91 const g: %?i32 = f;90 const g: error!?i32 = f;
9291
93 const a = A{ .a = z };92 const a = A{ .a = z };
94 const b: %?A = a;93 const b: error!?A = a;
95 assert((??(b catch unreachable)).a == 1);94 assert((??(b catch unreachable)).a == 1);
96}95}
9796
98test "implicitly cast from int to %?T" {97test "implicitly cast from int to error!?T" {
99 implicitIntLitToMaybe();98 implicitIntLitToMaybe();
100 comptime implicitIntLitToMaybe();99 comptime implicitIntLitToMaybe();
101}100}
102fn implicitIntLitToMaybe() void {101fn implicitIntLitToMaybe() void {
103 const f: ?i32 = 1;102 const f: ?i32 = 1;
104 const g: %?i32 = 1;103 const g: error!?i32 = 1;
105}104}
106105
107106
108test "return null from fn() %?&T" {107test "return null from fn() error!?&T" {
109 const a = returnNullFromMaybeTypeErrorRef();108 const a = returnNullFromMaybeTypeErrorRef();
110 const b = returnNullLitFromMaybeTypeErrorRef();109 const b = returnNullLitFromMaybeTypeErrorRef();
111 assert((try a) == null and (try b) == null);110 assert((try a) == null and (try b) == null);
112}111}
113fn returnNullFromMaybeTypeErrorRef() %?&A {112fn returnNullFromMaybeTypeErrorRef() error!?&A {
114 const a: ?&A = null;113 const a: ?&A = null;
115 return a;114 return a;
116}115}
117fn returnNullLitFromMaybeTypeErrorRef() %?&A {116fn returnNullLitFromMaybeTypeErrorRef() error!?&A {
118 return null;117 return null;
119}118}
120119
...@@ -161,7 +160,7 @@ fn castToMaybeSlice() ?[]const u8 {...@@ -161,7 +160,7 @@ fn castToMaybeSlice() ?[]const u8 {
161}160}
162161
163162
164test "implicitly cast from [0]T to %[]T" {163test "implicitly cast from [0]T to error![]T" {
165 testCastZeroArrayToErrSliceMut();164 testCastZeroArrayToErrSliceMut();
166 comptime testCastZeroArrayToErrSliceMut();165 comptime testCastZeroArrayToErrSliceMut();
167}166}
...@@ -170,11 +169,11 @@ fn testCastZeroArrayToErrSliceMut() void {...@@ -170,11 +169,11 @@ fn testCastZeroArrayToErrSliceMut() void {
170 assert((gimmeErrOrSlice() catch unreachable).len == 0);169 assert((gimmeErrOrSlice() catch unreachable).len == 0);
171}170}
172171
173fn gimmeErrOrSlice() %[]u8 {172fn gimmeErrOrSlice() error![]u8 {
174 return []u8{};173 return []u8{};
175}174}
176175
177test "peer type resolution: [0]u8, []const u8, and %[]u8" {176test "peer type resolution: [0]u8, []const u8, and error![]u8" {
178 {177 {
179 var data = "hi";178 var data = "hi";
180 const slice = data[0..];179 const slice = data[0..];
...@@ -188,7 +187,7 @@ test "peer type resolution: [0]u8, []const u8, and %[]u8" {...@@ -188,7 +187,7 @@ test "peer type resolution: [0]u8, []const u8, and %[]u8" {
188 assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);187 assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
189 }188 }
190}189}
191fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) %[]u8 {190fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) error![]u8 {
192 if (a) {191 if (a) {
193 return []u8{};192 return []u8{};
194 }193 }
...@@ -230,7 +229,7 @@ fn foo(args: ...) void {...@@ -230,7 +229,7 @@ fn foo(args: ...) void {
230229
231230
232test "peer type resolution: error and [N]T" {231test "peer type resolution: error and [N]T" {
233 // TODO: implicit %T to %U where T can implicitly cast to U232 // TODO: implicit error!T to error!U where T can implicitly cast to U
234 //assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));233 //assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
235 //comptime assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));234 //comptime assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
236235
...@@ -238,14 +237,13 @@ test "peer type resolution: error and [N]T" {...@@ -238,14 +237,13 @@ test "peer type resolution: error and [N]T" {
238 comptime assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));237 comptime assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
239}238}
240239
241error BadValue;240//fn testPeerErrorAndArray(x: u8) error![]const u8 {
242//fn testPeerErrorAndArray(x: u8) %[]const u8 {
243// return switch (x) {241// return switch (x) {
244// 0x00 => "OK",242// 0x00 => "OK",
245// else => error.BadValue,243// else => error.BadValue,
246// };244// };
247//}245//}
248fn testPeerErrorAndArray2(x: u8) %[]const u8 {246fn testPeerErrorAndArray2(x: u8) error![]const u8 {
249 return switch (x) {247 return switch (x) {
250 0x00 => "OK",248 0x00 => "OK",
251 0x01 => "OKK",249 0x01 => "OKK",
test/cases/defer.zig+1-3
...@@ -3,9 +3,7 @@ const assert = @import("std").debug.assert;...@@ -3,9 +3,7 @@ const assert = @import("std").debug.assert;
3var result: [3]u8 = undefined;3var result: [3]u8 = undefined;
4var index: usize = undefined;4var index: usize = undefined;
55
6error FalseNotAllowed;6fn runSomeErrorDefers(x: bool) !bool {
7
8fn runSomeErrorDefers(x: bool) %bool {
9 index = 0;7 index = 0;
10 defer {result[index] = 'a'; index += 1;}8 defer {result[index] = 'a'; index += 1;}
11 errdefer {result[index] = 'b'; index += 1;}9 errdefer {result[index] = 'b'; index += 1;}
test/cases/enum_with_members.zig+1-1
...@@ -6,7 +6,7 @@ const ET = union(enum) {...@@ -6,7 +6,7 @@ const ET = union(enum) {
6 SINT: i32,6 SINT: i32,
7 UINT: u32,7 UINT: u32,
88
9 pub fn print(a: &const ET, buf: []u8) %usize {9 pub fn print(a: &const ET, buf: []u8) error!usize {
10 return switch (*a) {10 return switch (*a) {
11 ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),11 ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
12 ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),12 ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
test/cases/error.zig+85-18
...@@ -1,16 +1,18 @@...@@ -1,16 +1,18 @@
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() %i32 {6pub fn foo() error!i32 {
5 const x = try bar();7 const x = try bar();
6 return x + 1;8 return x + 1;
7}9}
810
9pub fn bar() %i32 {11pub fn bar() error!i32 {
10 return 13;12 return 13;
11}13}
1214
13pub fn baz() %i32 {15pub fn baz() error!i32 {
14 const y = foo() catch 1234;16 const y = foo() catch 1234;
15 return y + 1;17 return y + 1;
16}18}
...@@ -19,7 +21,6 @@ test "error wrapping" {...@@ -19,7 +21,6 @@ test "error wrapping" {
19 assert((baz() catch unreachable) == 15);21 assert((baz() catch unreachable) == 15);
20}22}
2123
22error ItBroke;
23fn gimmeItBroke() []const u8 {24fn gimmeItBroke() []const u8 {
24 return @errorName(error.ItBroke);25 return @errorName(error.ItBroke);
25}26}
...@@ -28,8 +29,6 @@ test "@errorName" {...@@ -28,8 +29,6 @@ test "@errorName" {
28 assert(mem.eql(u8, @errorName(error.AnError), "AnError"));29 assert(mem.eql(u8, @errorName(error.AnError), "AnError"));
29 assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));30 assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
30}31}
31error AnError;
32error ALongerErrorName;
3332
3433
35test "error values" {34test "error values" {
...@@ -37,16 +36,11 @@ test "error values" {...@@ -37,16 +36,11 @@ test "error values" {
37 const b = i32(error.err2);36 const b = i32(error.err2);
38 assert(a != b);37 assert(a != b);
39}38}
40error err1;
41error err2;
4239
4340
44test "redefinition of error values allowed" {41test "redefinition of error values allowed" {
45 shouldBeNotEqual(error.AnError, error.SecondError);42 shouldBeNotEqual(error.AnError, error.SecondError);
46}43}
47error AnError;
48error AnError;
49error SecondError;
50fn shouldBeNotEqual(a: error, b: error) void {44fn shouldBeNotEqual(a: error, b: error) void {
51 if (a == b) unreachable;45 if (a == b) unreachable;
52}46}
...@@ -58,8 +52,7 @@ test "error binary operator" {...@@ -58,8 +52,7 @@ test "error binary operator" {
58 assert(a == 3);52 assert(a == 3);
59 assert(b == 10);53 assert(b == 10);
60}54}
61error ItBroke;55fn errBinaryOperatorG(x: bool) error!isize {
62fn errBinaryOperatorG(x: bool) %isize {
63 return if (x) error.ItBroke else isize(10);56 return if (x) error.ItBroke else isize(10);
64}57}
6558
...@@ -68,18 +61,92 @@ test "unwrap simple value from error" {...@@ -68,18 +61,92 @@ test "unwrap simple value from error" {
68 const i = unwrapSimpleValueFromErrorDo() catch unreachable;61 const i = unwrapSimpleValueFromErrorDo() catch unreachable;
69 assert(i == 13);62 assert(i == 13);
70}63}
71fn unwrapSimpleValueFromErrorDo() %isize { return 13; }64fn unwrapSimpleValueFromErrorDo() error!isize { return 13; }
7265
7366
74test "error return in assignment" {67test "error return in assignment" {
75 doErrReturnInAssignment() catch unreachable;68 doErrReturnInAssignment() catch unreachable;
76}69}
7770
78fn doErrReturnInAssignment() %void {71fn doErrReturnInAssignment() error!void {
79 var x : i32 = undefined;72 var x : i32 = undefined;
80 x = try makeANonErr();73 x = try makeANonErr();
81}74}
8275
83fn makeANonErr() %i32 {76fn makeANonErr() error!i32 {
84 return 1;77 return 1;
85}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}
111
112
113test "explicit error set cast" {
114 testExplicitErrorSetCast(Set1.A);
115 comptime testExplicitErrorSetCast(Set1.A);
116}
117
118const Set1 = error{A, B};
119const Set2 = error{A, C};
120
121fn testExplicitErrorSetCast(set1: Set1) void {
122 var x = Set2(set1);
123 var y = Set1(x);
124 assert(y == error.A);
125}
126
127test "comptime test error for empty error set" {
128 testComptimeTestErrorEmptySet(1234);
129 comptime testComptimeTestErrorEmptySet(1234);
130}
131
132const EmptyErrorSet = error {};
133
134fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void {
135 if (x) |v| assert(v == 1234) else |err| @compileError("bad");
136}
137
138test "syntax: nullable operator in front of error union operator" {
139 comptime {
140 assert(?error!i32 == ?(error!i32));
141 }
142}
143
144test "comptime err to int of error set with only 1 possible value" {
145 testErrToIntWithOnePossibleValue(error.A, u32(error.A));
146 comptime testErrToIntWithOnePossibleValue(error.A, u32(error.A));
147}
148fn testErrToIntWithOnePossibleValue(x: error{A}, comptime value: u32) void {
149 if (u32(x) != value) {
150 @compileError("bad");
151 }
152}
test/cases/ir_block_deps.zig+2-4
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const assert = @import("std").debug.assert;1const assert = @import("std").debug.assert;
22
3fn foo(id: u64) %i32 {3fn foo(id: u64) !i32 {
4 return switch (id) {4 return switch (id) {
5 1 => getErrInt(),5 1 => getErrInt(),
6 2 => {6 2 => {
...@@ -11,9 +11,7 @@ fn foo(id: u64) %i32 {...@@ -11,9 +11,7 @@ fn foo(id: u64) %i32 {
11 };11 };
12}12}
1313
14fn getErrInt() %i32 { return 0; }14fn getErrInt() error!i32 { return 0; }
15
16error ItBroke;
1715
18test "ir block deps" {16test "ir block deps" {
19 assert((foo(1) catch unreachable) == 0);17 assert((foo(1) catch unreachable) == 0);
test/cases/misc.zig+4-4
...@@ -262,7 +262,7 @@ test "generic malloc free" {...@@ -262,7 +262,7 @@ test "generic malloc free" {
262 memFree(u8, a);262 memFree(u8, a);
263}263}
264const some_mem : [100]u8 = undefined;264const some_mem : [100]u8 = undefined;
265fn memAlloc(comptime T: type, n: usize) %[]T {265fn memAlloc(comptime T: type, n: usize) error![]T {
266 return @ptrCast(&T, &some_mem[0])[0..n];266 return @ptrCast(&T, &some_mem[0])[0..n];
267}267}
268fn memFree(comptime T: type, memory: []T) void { }268fn memFree(comptime T: type, memory: []T) void { }
...@@ -419,7 +419,7 @@ test "cast slice to u8 slice" {...@@ -419,7 +419,7 @@ test "cast slice to u8 slice" {
419test "pointer to void return type" {419test "pointer to void return type" {
420 testPointerToVoidReturnType() catch unreachable;420 testPointerToVoidReturnType() catch unreachable;
421}421}
422fn testPointerToVoidReturnType() %void {422fn testPointerToVoidReturnType() error!void {
423 const a = testPointerToVoidReturnType2();423 const a = testPointerToVoidReturnType2();
424 return *a;424 return *a;
425}425}
...@@ -475,8 +475,8 @@ test "@typeId" {...@@ -475,8 +475,8 @@ test "@typeId" {
475 assert(@typeId(@typeOf(undefined)) == Tid.UndefinedLiteral);475 assert(@typeId(@typeOf(undefined)) == Tid.UndefinedLiteral);
476 assert(@typeId(@typeOf(null)) == Tid.NullLiteral);476 assert(@typeId(@typeOf(null)) == Tid.NullLiteral);
477 assert(@typeId(?i32) == Tid.Nullable);477 assert(@typeId(?i32) == Tid.Nullable);
478 assert(@typeId(%i32) == Tid.ErrorUnion);478 assert(@typeId(error!i32) == Tid.ErrorUnion);
479 assert(@typeId(error) == Tid.Error);479 assert(@typeId(error) == Tid.ErrorSet);
480 assert(@typeId(AnEnum) == Tid.Enum);480 assert(@typeId(AnEnum) == Tid.Enum);
481 assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);481 assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
482 assert(@typeId(AUnionEnum) == Tid.Union);482 assert(@typeId(AUnionEnum) == Tid.Union);
test/cases/reflection.zig+1-1
...@@ -5,7 +5,7 @@ test "reflection: array, pointer, nullable, error union type child" {...@@ -5,7 +5,7 @@ test "reflection: array, pointer, nullable, error union type child" {
5 comptime {5 comptime {
6 assert(([10]u8).Child == u8);6 assert(([10]u8).Child == u8);
7 assert((&u8).Child == u8);7 assert((&u8).Child == u8);
8 assert((%u8).Child == u8);8 assert((error!u8).Payload == u8);
9 assert((?u8).Child == u8);9 assert((?u8).Child == u8);
10 }10 }
11}11}
test/cases/switch.zig+1-1
...@@ -225,7 +225,7 @@ fn switchWithUnreachable(x: i32) i32 {...@@ -225,7 +225,7 @@ fn switchWithUnreachable(x: i32) i32 {
225 return 10;225 return 10;
226}226}
227227
228fn return_a_number() %i32 {228fn return_a_number() error!i32 {
229 return 1;229 return 1;
230}230}
231231
test/cases/switch_prong_err_enum.zig+2-4
...@@ -2,19 +2,17 @@ const assert = @import("std").debug.assert;...@@ -2,19 +2,17 @@ const assert = @import("std").debug.assert;
22
3var read_count: u64 = 0;3var read_count: u64 = 0;
44
5fn readOnce() %u64 {5fn readOnce() error!u64 {
6 read_count += 1;6 read_count += 1;
7 return read_count;7 return read_count;
8}8}
99
10error InvalidDebugInfo;
11
12const FormValue = union(enum) {10const FormValue = union(enum) {
13 Address: u64,11 Address: u64,
14 Other: bool,12 Other: bool,
15};13};
1614
17fn doThing(form_id: u64) %FormValue {15fn doThing(form_id: u64) error!FormValue {
18 return switch (form_id) {16 return switch (form_id) {
19 17 => FormValue { .Address = try readOnce() },17 17 => FormValue { .Address = try readOnce() },
20 else => error.InvalidDebugInfo,18 else => error.InvalidDebugInfo,
test/cases/switch_prong_implicit_cast.zig+1-3
...@@ -5,9 +5,7 @@ const FormValue = union(enum) {...@@ -5,9 +5,7 @@ const FormValue = union(enum) {
5 Two: bool,5 Two: bool,
6};6};
77
8error Whatever;8fn foo(id: u64) !FormValue {
9
10fn foo(id: u64) %FormValue {
11 return switch (id) {9 return switch (id) {
12 2 => FormValue { .Two = true },10 2 => FormValue { .Two = true },
13 1 => FormValue { .One = {} },11 1 => FormValue { .One = {} },
test/cases/try.zig+2-5
...@@ -17,10 +17,7 @@ fn tryOnErrorUnionImpl() void {...@@ -17,10 +17,7 @@ fn tryOnErrorUnionImpl() void {
17 assert(x == 11);17 assert(x == 11);
18}18}
1919
20error ItBroke;20fn returnsTen() error!i32 {
21error NoMem;
22error CrappedOut;
23fn returnsTen() %i32 {
24 return 10;21 return 10;
25}22}
2623
...@@ -32,7 +29,7 @@ test "try without vars" {...@@ -32,7 +29,7 @@ test "try without vars" {
32 assert(result2 == 1);29 assert(result2 == 1);
33}30}
3431
35fn failIfTrue(ok: bool) %void {32fn failIfTrue(ok: bool) error!void {
36 if (ok) {33 if (ok) {
37 return error.ItBroke;34 return error.ItBroke;
38 } else {35 } else {
test/cases/union.zig+1-1
...@@ -13,7 +13,7 @@ const Agg = struct {...@@ -13,7 +13,7 @@ const Agg = struct {
13const v1 = Value { .Int = 1234 };13const v1 = Value { .Int = 1234 };
14const v2 = Value { .Array = []u8{3} ** 9 };14const v2 = Value { .Array = []u8{3} ** 9 };
1515
16const err = (%Agg)(Agg {16const err = (error!Agg)(Agg {
17 .val1 = v1,17 .val1 = v1,
18 .val2 = v2,18 .val2 = v2,
19});19});
test/cases/while.zig+4-6
...@@ -50,7 +50,7 @@ fn runContinueAndBreakTest() void {...@@ -50,7 +50,7 @@ fn runContinueAndBreakTest() void {
50test "return with implicit cast from while loop" {50test "return with implicit cast from while loop" {
51 returnWithImplicitCastFromWhileLoopTest() catch unreachable;51 returnWithImplicitCastFromWhileLoopTest() catch unreachable;
52}52}
53fn returnWithImplicitCastFromWhileLoopTest() %void {53fn returnWithImplicitCastFromWhileLoopTest() error!void {
54 while (true) {54 while (true) {
55 return;55 return;
56 }56 }
...@@ -116,8 +116,7 @@ test "while with error union condition" {...@@ -116,8 +116,7 @@ test "while with error union condition" {
116}116}
117117
118var numbers_left: i32 = undefined;118var numbers_left: i32 = undefined;
119error OutOfNumbers;119fn getNumberOrErr() error!i32 {
120fn getNumberOrErr() %i32 {
121 return if (numbers_left == 0)120 return if (numbers_left == 0)
122 error.OutOfNumbers121 error.OutOfNumbers
123 else x: {122 else x: {
...@@ -205,8 +204,7 @@ fn testContinueOuter() void {...@@ -205,8 +204,7 @@ fn testContinueOuter() void {
205204
206fn returnNull() ?i32 { return null; }205fn returnNull() ?i32 { return null; }
207fn returnMaybe(x: i32) ?i32 { return x; }206fn returnMaybe(x: i32) ?i32 { return x; }
208error YouWantedAnError;207fn returnError() error!i32 { return error.YouWantedAnError; }
209fn returnError() %i32 { return error.YouWantedAnError; }208fn returnSuccess(x: i32) error!i32 { return x; }
210fn returnSuccess(x: i32) %i32 { return x; }
211fn returnFalse() bool { return false; }209fn returnFalse() bool { return false; }
212fn returnTrue() bool { return true; }210fn returnTrue() bool { return true; }
test/compare_output.zig+17-18
...@@ -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,10 +394,10 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -394,10 +394,10 @@ 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 {
401 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);401 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
402 \\ stdout.print("before\n") catch unreachable;402 \\ stdout.print("before\n") catch unreachable;
403 \\ defer stdout.print("defer1\n") catch unreachable;403 \\ defer stdout.print("defer1\n") catch unreachable;
...@@ -406,18 +406,17 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -406,18 +406,17 @@ 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;409 \\fn its_gonna_fail() !void {
410 \\fn its_gonna_fail() %void {
411 \\ return error.IToldYouItWouldFail;410 \\ return error.IToldYouItWouldFail;
412 \\}411 \\}
413 , "before\ndeferErr\ndefer1\n");412 , "before\ndeferErr\ndefer1\n");
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 {
421 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);420 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
422 \\ stdout.print("before\n") catch unreachable;421 \\ stdout.print("before\n") catch unreachable;
423 \\ defer stdout.print("defer1\n") catch unreachable;422 \\ defer stdout.print("defer1\n") catch unreachable;
...@@ -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 \\}
...@@ -452,7 +451,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -452,7 +451,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
452 \\const os = std.os;451 \\const os = std.os;
453 \\const allocator = std.debug.global_allocator;452 \\const allocator = std.debug.global_allocator;
454 \\453 \\
455 \\pub fn main() %void {454 \\pub fn main() !void {
456 \\ var args_it = os.args();455 \\ var args_it = os.args();
457 \\ var stdout_file = try io.getStdOut();456 \\ var stdout_file = try io.getStdOut();
458 \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);457 \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);
...@@ -493,7 +492,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -493,7 +492,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
493 \\const os = std.os;492 \\const os = std.os;
494 \\const allocator = std.debug.global_allocator;493 \\const allocator = std.debug.global_allocator;
495 \\494 \\
496 \\pub fn main() %void {495 \\pub fn main() !void {
497 \\ var args_it = os.args();496 \\ var args_it = os.args();
498 \\ var stdout_file = try io.getStdOut();497 \\ var stdout_file = try io.getStdOut();
499 \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);498 \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);
test/compile_errors.zig+219-18
...@@ -1,6 +1,208 @@...@@ -1,6 +1,208 @@
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("inferred error set with no returned error",
5 \\export fn entry() void {
6 \\ foo() catch unreachable;
7 \\}
8 \\fn foo() !void {
9 \\}
10 ,
11 ".tmp_source.zig:4:11: error: function with inferred error set must return at least one possible error");
12
13 cases.add("error not handled in switch",
14 \\export fn entry() void {
15 \\ foo(452) catch |err| switch (err) {
16 \\ error.Foo => {},
17 \\ };
18 \\}
19 \\fn foo(x: i32) !void {
20 \\ switch (x) {
21 \\ 0 ... 10 => return error.Foo,
22 \\ 11 ... 20 => return error.Bar,
23 \\ 21 ... 30 => return error.Baz,
24 \\ else => {},
25 \\ }
26 \\}
27 ,
28 ".tmp_source.zig:2:26: error: error.Baz not handled in switch",
29 ".tmp_source.zig:2:26: error: error.Bar not handled in switch");
30
31 cases.add("duplicate error in switch",
32 \\export fn entry() void {
33 \\ foo(452) catch |err| switch (err) {
34 \\ error.Foo => {},
35 \\ error.Bar => {},
36 \\ error.Foo => {},
37 \\ else => {},
38 \\ };
39 \\}
40 \\fn foo(x: i32) !void {
41 \\ switch (x) {
42 \\ 0 ... 10 => return error.Foo,
43 \\ 11 ... 20 => return error.Bar,
44 \\ else => {},
45 \\ }
46 \\}
47 ,
48 ".tmp_source.zig:5:14: error: duplicate switch value: '@typeOf(foo).ReturnType.ErrorSet.Foo'",
49 ".tmp_source.zig:3:14: note: other value is here");
50
51 cases.add("range operator in switch used on error set",
52 \\export fn entry() void {
53 \\ try foo(452) catch |err| switch (err) {
54 \\ error.A ... error.B => {},
55 \\ else => {},
56 \\ };
57 \\}
58 \\fn foo(x: i32) !void {
59 \\ switch (x) {
60 \\ 0 ... 10 => return error.Foo,
61 \\ 11 ... 20 => return error.Bar,
62 \\ else => {},
63 \\ }
64 \\}
65 ,
66 ".tmp_source.zig:3:17: error: operator not allowed for errors");
67
68 cases.add("inferring error set of function pointer",
69 \\comptime {
70 \\ const z: ?fn()!void = null;
71 \\}
72 ,
73 ".tmp_source.zig:2:15: error: inferring error set of return type valid only for function definitions");
74
75 cases.add("access non-existent member of error set",
76 \\const Foo = error{A};
77 \\comptime {
78 \\ const z = Foo.Bar;
79 \\}
80 ,
81 ".tmp_source.zig:3:18: error: no error named 'Bar' in 'Foo'");
82
83 cases.add("error union operator with non error set LHS",
84 \\comptime {
85 \\ const z = i32!i32;
86 \\}
87 ,
88 ".tmp_source.zig:2:15: error: expected error set type, found type 'i32'");
89
90 cases.add("error equality but sets have no common members",
91 \\const Set1 = error{A, C};
92 \\const Set2 = error{B, D};
93 \\export fn entry() void {
94 \\ foo(Set1.A);
95 \\}
96 \\fn foo(x: Set1) void {
97 \\ if (x == Set2.B) {
98 \\
99 \\ }
100 \\}
101 ,
102 ".tmp_source.zig:7:11: error: error sets 'Set1' and 'Set2' have no common errors");
103
104 cases.add("only equality binary operator allowed for error sets",
105 \\comptime {
106 \\ const z = error.A > error.B;
107 \\}
108 ,
109 ".tmp_source.zig:2:23: error: operator not allowed for errors");
110
111 cases.add("explicit error set cast known at comptime violates error sets",
112 \\const Set1 = error {A, B};
113 \\const Set2 = error {A, C};
114 \\comptime {
115 \\ var x = Set1.B;
116 \\ var y = Set2(x);
117 \\}
118 ,
119 ".tmp_source.zig:5:17: error: error.B not a member of error set 'Set2'");
120
121 cases.add("cast error union of global error set to error union of smaller error set",
122 \\const SmallErrorSet = error{A};
123 \\export fn entry() void {
124 \\ var x: SmallErrorSet!i32 = foo();
125 \\}
126 \\fn foo() error!i32 {
127 \\ return error.B;
128 \\}
129 ,
130 ".tmp_source.zig:3:35: error: expected 'SmallErrorSet!i32', found 'error!i32'",
131 ".tmp_source.zig:3:35: note: unable to cast global error set into smaller set");
132
133 cases.add("cast global error set to error set",
134 \\const SmallErrorSet = error{A};
135 \\export fn entry() void {
136 \\ var x: SmallErrorSet = foo();
137 \\}
138 \\fn foo() error {
139 \\ return error.B;
140 \\}
141 ,
142 ".tmp_source.zig:3:31: error: expected 'SmallErrorSet', found 'error'",
143 ".tmp_source.zig:3:31: note: unable to cast global error set into smaller set");
144
145 cases.add("recursive inferred error set",
146 \\export fn entry() void {
147 \\ foo() catch unreachable;
148 \\}
149 \\fn foo() !void {
150 \\ try foo();
151 \\}
152 ,
153 ".tmp_source.zig:5:5: error: cannot resolve inferred error set '@typeOf(foo).ReturnType.ErrorSet': function 'foo' not fully analyzed yet");
154
155 cases.add("implicit cast of error set not a subset",
156 \\const Set1 = error{A, B};
157 \\const Set2 = error{A, C};
158 \\export fn entry() void {
159 \\ foo(Set1.B);
160 \\}
161 \\fn foo(set1: Set1) void {
162 \\ var x: Set2 = set1;
163 \\}
164 ,
165 ".tmp_source.zig:7:19: error: expected 'Set2', found 'Set1'",
166 ".tmp_source.zig:1:23: note: 'error.B' not a member of destination error set");
167
168 cases.add("int to err global invalid number",
169 \\const Set1 = error{A, B};
170 \\comptime {
171 \\ var x: usize = 3;
172 \\ var y = error(x);
173 \\}
174 ,
175 ".tmp_source.zig:4:18: error: integer value 3 represents no error");
176
177 cases.add("int to err non global invalid number",
178 \\const Set1 = error{A, B};
179 \\const Set2 = error{A, C};
180 \\comptime {
181 \\ var x = usize(Set1.B);
182 \\ var y = Set2(x);
183 \\}
184 ,
185 ".tmp_source.zig:5:17: error: integer value 2 represents no error in 'Set2'");
186
187 cases.add("@memberCount of error",
188 \\comptime {
189 \\ _ = @memberCount(error);
190 \\}
191 ,
192 ".tmp_source.zig:2:9: error: global error set member count not available at comptime");
193
194 cases.add("duplicate error value in error set",
195 \\const Foo = error {
196 \\ Bar,
197 \\ Bar,
198 \\};
199 \\export fn entry() void {
200 \\ const a: Foo = undefined;
201 \\}
202 ,
203 ".tmp_source.zig:3:5: error: duplicate error: 'Bar'",
204 ".tmp_source.zig:2:5: note: other error here");
205
4 cases.add("cast negative integer literal to usize",206 cases.add("cast negative integer literal to usize",
5 \\export fn entry() void {207 \\export fn entry() void {
6 \\ const x = usize(-10);208 \\ const x = usize(-10);
...@@ -112,12 +314,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -112,12 +314,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
112314
113 cases.add("wrong return type for main",315 cases.add("wrong return type for main",
114 \\pub fn main() f32 { }316 \\pub fn main() f32 { }
115 , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '%void'");317 , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '!void'");
116318
117 cases.add("double ?? on main return value",319 cases.add("double ?? on main return value",
118 \\pub fn main() ??void {320 \\pub fn main() ??void {
119 \\}321 \\}
120 , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '%void'");322 , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '!void'");
121323
122 cases.add("bad identifier in function with struct defined inside function which references local const",324 cases.add("bad identifier in function with struct defined inside function which references local const",
123 \\export fn entry() void {325 \\export fn entry() void {
...@@ -1173,7 +1375,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1173,7 +1375,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1173 \\export fn f() void {1375 \\export fn f() void {
1174 \\ try something();1376 \\ try something();
1175 \\}1377 \\}
1176 \\fn something() %void { }1378 \\fn something() error!void { }
1177 ,1379 ,
1178 ".tmp_source.zig:2:5: error: expected type 'void', found 'error'");1380 ".tmp_source.zig:2:5: error: expected type 'void', found 'error'");
11791381
...@@ -1264,7 +1466,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1264,7 +1466,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1264 , ".tmp_source.zig:3:11: error: cannot assign to constant");1466 , ".tmp_source.zig:3:11: error: cannot assign to constant");
12651467
1266 cases.add("main function with bogus args type",1468 cases.add("main function with bogus args type",
1267 \\pub fn main(args: [][]bogus) %void {}1469 \\pub fn main(args: [][]bogus) !void {}
1268 , ".tmp_source.zig:1:23: error: use of undeclared identifier 'bogus'");1470 , ".tmp_source.zig:1:23: error: use of undeclared identifier 'bogus'");
12691471
1270 cases.add("for loop missing element param",1472 cases.add("for loop missing element param",
...@@ -1396,7 +1598,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1396,7 +1598,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1396 , ".tmp_source.zig:6:13: error: cannot assign to constant");1598 , ".tmp_source.zig:6:13: error: cannot assign to constant");
13971599
1398 cases.add("return from defer expression",1600 cases.add("return from defer expression",
1399 \\pub fn testTrickyDefer() %void {1601 \\pub fn testTrickyDefer() !void {
1400 \\ defer canFail() catch {};1602 \\ defer canFail() catch {};
1401 \\1603 \\
1402 \\ defer try canFail();1604 \\ defer try canFail();
...@@ -1404,7 +1606,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1404,7 +1606,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1404 \\ const a = maybeInt() ?? return;1606 \\ const a = maybeInt() ?? return;
1405 \\}1607 \\}
1406 \\1608 \\
1407 \\fn canFail() %void { }1609 \\fn canFail() error!void { }
1408 \\1610 \\
1409 \\pub fn maybeInt() ?i32 {1611 \\pub fn maybeInt() ?i32 {
1410 \\ return 0;1612 \\ return 0;
...@@ -1534,7 +1736,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1534,7 +1736,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1534 \\export fn foo() void {1736 \\export fn foo() void {
1535 \\ bar() catch unreachable;1737 \\ bar() catch unreachable;
1536 \\}1738 \\}
1537 \\fn bar() %i32 { return 0; }1739 \\fn bar() error!i32 { return 0; }
1538 , ".tmp_source.zig:2:11: error: expression value is ignored");1740 , ".tmp_source.zig:2:11: error: expression value is ignored");
15391741
1540 cases.add("ignored statement value",1742 cases.add("ignored statement value",
...@@ -1565,7 +1767,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1565,7 +1767,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1565 \\export fn foo() void {1767 \\export fn foo() void {
1566 \\ defer bar();1768 \\ defer bar();
1567 \\}1769 \\}
1568 \\fn bar() %i32 { return 0; }1770 \\fn bar() error!i32 { return 0; }
1569 , ".tmp_source.zig:2:14: error: expression value is ignored");1771 , ".tmp_source.zig:2:14: error: expression value is ignored");
15701772
1571 cases.add("dereference an array",1773 cases.add("dereference an array",
...@@ -1632,13 +1834,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1632,13 +1834,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1632 , ".tmp_source.zig:2:21: error: expected pointer, found 'usize'");1834 , ".tmp_source.zig:2:21: error: expected pointer, found 'usize'");
16331835
1634 cases.add("too many error values to cast to small integer",1836 cases.add("too many error values to cast to small integer",
1635 \\error A; error B; error C; error D; error E; error F; error G; error H;1837 \\const Error = error { A, B, C, D, E, F, G, H };
1636 \\const u2 = @IntType(false, 2);1838 \\fn foo(e: Error) u2 {
1637 \\fn foo(e: error) u2 {
1638 \\ return u2(e);1839 \\ return u2(e);
1639 \\}1840 \\}
1640 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }1841 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
1641 , ".tmp_source.zig:4:14: error: too many error values to fit in 'u2'");1842 , ".tmp_source.zig:3:14: error: too many error values to fit in 'u2'");
16421843
1643 cases.add("asm at compile time",1844 cases.add("asm at compile time",
1644 \\comptime {1845 \\comptime {
...@@ -1821,9 +2022,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1821,9 +2022,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1821 \\export fn foo() void {2022 \\export fn foo() void {
1822 \\ while (bar()) {}2023 \\ while (bar()) {}
1823 \\}2024 \\}
1824 \\fn bar() %i32 { return 1; }2025 \\fn bar() error!i32 { return 1; }
1825 ,2026 ,
1826 ".tmp_source.zig:2:15: error: expected type 'bool', found '%i32'");2027 ".tmp_source.zig:2:15: error: expected type 'bool', found 'error!i32'");
18272028
1828 cases.add("while expected nullable, got bool",2029 cases.add("while expected nullable, got bool",
1829 \\export fn foo() void {2030 \\export fn foo() void {
...@@ -1837,9 +2038,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1837,9 +2038,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1837 \\export fn foo() void {2038 \\export fn foo() void {
1838 \\ while (bar()) |x| {}2039 \\ while (bar()) |x| {}
1839 \\}2040 \\}
1840 \\fn bar() %i32 { return 1; }2041 \\fn bar() error!i32 { return 1; }
1841 ,2042 ,
1842 ".tmp_source.zig:2:15: error: expected nullable type, found '%i32'");2043 ".tmp_source.zig:2:15: error: expected nullable type, found 'error!i32'");
18432044
1844 cases.add("while expected error union, got bool",2045 cases.add("while expected error union, got bool",
1845 \\export fn foo() void {2046 \\export fn foo() void {
...@@ -1983,7 +2184,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1983,7 +2184,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1983 \\fn foo1(args: ...) void {}2184 \\fn foo1(args: ...) void {}
1984 \\fn foo2(args: ...) void {}2185 \\fn foo2(args: ...) void {}
1985 \\2186 \\
1986 \\pub fn main() %void {2187 \\pub fn main() !void {
1987 \\ foos[0]();2188 \\ foos[0]();
1988 \\}2189 \\}
1989 ,2190 ,
...@@ -1995,7 +2196,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1995,7 +2196,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1995 \\fn foo1(arg: var) void {}2196 \\fn foo1(arg: var) void {}
1996 \\fn foo2(arg: var) void {}2197 \\fn foo2(arg: var) void {}
1997 \\2198 \\
1998 \\pub fn main() %void {2199 \\pub fn main() !void {
1999 \\ foos[0](true);2200 \\ foos[0](true);
2000 \\}2201 \\}
2001 ,2202 ,
test/runtime_safety.zig+36-38
...@@ -5,7 +5,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -5,7 +5,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
5 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {5 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
6 \\ @import("std").os.exit(126);6 \\ @import("std").os.exit(126);
7 \\}7 \\}
8 \\pub fn main() %void {8 \\pub fn main() void {
9 \\ @panic("oh no");9 \\ @panic("oh no");
10 \\}10 \\}
11 );11 );
...@@ -14,7 +14,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -14,7 +14,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
14 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {14 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
15 \\ @import("std").os.exit(126);15 \\ @import("std").os.exit(126);
16 \\}16 \\}
17 \\pub fn main() %void {17 \\pub fn main() void {
18 \\ const a = []i32{1, 2, 3, 4};18 \\ const a = []i32{1, 2, 3, 4};
19 \\ baz(bar(a));19 \\ baz(bar(a));
20 \\}20 \\}
...@@ -28,8 +28,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -28,8 +28,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
28 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {28 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
29 \\ @import("std").os.exit(126);29 \\ @import("std").os.exit(126);
30 \\}30 \\}
31 \\error Whatever;31 \\pub fn main() !void {
32 \\pub fn main() %void {
33 \\ const x = add(65530, 10);32 \\ const x = add(65530, 10);
34 \\ if (x == 0) return error.Whatever;33 \\ if (x == 0) return error.Whatever;
35 \\}34 \\}
...@@ -42,8 +41,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -42,8 +41,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
42 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {41 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
43 \\ @import("std").os.exit(126);42 \\ @import("std").os.exit(126);
44 \\}43 \\}
45 \\error Whatever;44 \\pub fn main() !void {
46 \\pub fn main() %void {
47 \\ const x = sub(10, 20);45 \\ const x = sub(10, 20);
48 \\ if (x == 0) return error.Whatever;46 \\ if (x == 0) return error.Whatever;
49 \\}47 \\}
...@@ -56,8 +54,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -56,8 +54,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
56 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {54 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
57 \\ @import("std").os.exit(126);55 \\ @import("std").os.exit(126);
58 \\}56 \\}
59 \\error Whatever;57 \\pub fn main() !void {
60 \\pub fn main() %void {
61 \\ const x = mul(300, 6000);58 \\ const x = mul(300, 6000);
62 \\ if (x == 0) return error.Whatever;59 \\ if (x == 0) return error.Whatever;
63 \\}60 \\}
...@@ -70,8 +67,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -70,8 +67,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
70 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {67 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
71 \\ @import("std").os.exit(126);68 \\ @import("std").os.exit(126);
72 \\}69 \\}
73 \\error Whatever;70 \\pub fn main() !void {
74 \\pub fn main() %void {
75 \\ const x = neg(-32768);71 \\ const x = neg(-32768);
76 \\ if (x == 32767) return error.Whatever;72 \\ if (x == 32767) return error.Whatever;
77 \\}73 \\}
...@@ -84,8 +80,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -84,8 +80,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
84 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {80 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
85 \\ @import("std").os.exit(126);81 \\ @import("std").os.exit(126);
86 \\}82 \\}
87 \\error Whatever;83 \\pub fn main() !void {
88 \\pub fn main() %void {
89 \\ const x = div(-32768, -1);84 \\ const x = div(-32768, -1);
90 \\ if (x == 32767) return error.Whatever;85 \\ if (x == 32767) return error.Whatever;
91 \\}86 \\}
...@@ -98,8 +93,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -98,8 +93,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
98 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {93 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
99 \\ @import("std").os.exit(126);94 \\ @import("std").os.exit(126);
100 \\}95 \\}
101 \\error Whatever;96 \\pub fn main() !void {
102 \\pub fn main() %void {
103 \\ const x = shl(-16385, 1);97 \\ const x = shl(-16385, 1);
104 \\ if (x == 0) return error.Whatever;98 \\ if (x == 0) return error.Whatever;
105 \\}99 \\}
...@@ -112,8 +106,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -112,8 +106,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
112 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {106 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
113 \\ @import("std").os.exit(126);107 \\ @import("std").os.exit(126);
114 \\}108 \\}
115 \\error Whatever;109 \\pub fn main() !void {
116 \\pub fn main() %void {
117 \\ const x = shl(0b0010111111111111, 3);110 \\ const x = shl(0b0010111111111111, 3);
118 \\ if (x == 0) return error.Whatever;111 \\ if (x == 0) return error.Whatever;
119 \\}112 \\}
...@@ -126,8 +119,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -126,8 +119,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
126 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {119 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
127 \\ @import("std").os.exit(126);120 \\ @import("std").os.exit(126);
128 \\}121 \\}
129 \\error Whatever;122 \\pub fn main() !void {
130 \\pub fn main() %void {
131 \\ const x = shr(-16385, 1);123 \\ const x = shr(-16385, 1);
132 \\ if (x == 0) return error.Whatever;124 \\ if (x == 0) return error.Whatever;
133 \\}125 \\}
...@@ -140,8 +132,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -140,8 +132,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
140 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {132 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
141 \\ @import("std").os.exit(126);133 \\ @import("std").os.exit(126);
142 \\}134 \\}
143 \\error Whatever;135 \\pub fn main() !void {
144 \\pub fn main() %void {
145 \\ const x = shr(0b0010111111111111, 3);136 \\ const x = shr(0b0010111111111111, 3);
146 \\ if (x == 0) return error.Whatever;137 \\ if (x == 0) return error.Whatever;
147 \\}138 \\}
...@@ -154,8 +145,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -154,8 +145,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
154 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {145 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
155 \\ @import("std").os.exit(126);146 \\ @import("std").os.exit(126);
156 \\}147 \\}
157 \\error Whatever;148 \\pub fn main() void {
158 \\pub fn main() %void {
159 \\ const x = div0(999, 0);149 \\ const x = div0(999, 0);
160 \\}150 \\}
161 \\fn div0(a: i32, b: i32) i32 {151 \\fn div0(a: i32, b: i32) i32 {
...@@ -167,8 +157,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -167,8 +157,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
167 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {157 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
168 \\ @import("std").os.exit(126);158 \\ @import("std").os.exit(126);
169 \\}159 \\}
170 \\error Whatever;160 \\pub fn main() !void {
171 \\pub fn main() %void {
172 \\ const x = divExact(10, 3);161 \\ const x = divExact(10, 3);
173 \\ if (x == 0) return error.Whatever;162 \\ if (x == 0) return error.Whatever;
174 \\}163 \\}
...@@ -181,8 +170,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -181,8 +170,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
181 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {170 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
182 \\ @import("std").os.exit(126);171 \\ @import("std").os.exit(126);
183 \\}172 \\}
184 \\error Whatever;173 \\pub fn main() !void {
185 \\pub fn main() %void {
186 \\ const x = widenSlice([]u8{1, 2, 3, 4, 5});174 \\ const x = widenSlice([]u8{1, 2, 3, 4, 5});
187 \\ if (x.len == 0) return error.Whatever;175 \\ if (x.len == 0) return error.Whatever;
188 \\}176 \\}
...@@ -195,8 +183,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -195,8 +183,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
195 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {183 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
196 \\ @import("std").os.exit(126);184 \\ @import("std").os.exit(126);
197 \\}185 \\}
198 \\error Whatever;186 \\pub fn main() !void {
199 \\pub fn main() %void {
200 \\ const x = shorten_cast(200);187 \\ const x = shorten_cast(200);
201 \\ if (x == 0) return error.Whatever;188 \\ if (x == 0) return error.Whatever;
202 \\}189 \\}
...@@ -209,8 +196,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -209,8 +196,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
209 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {196 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
210 \\ @import("std").os.exit(126);197 \\ @import("std").os.exit(126);
211 \\}198 \\}
212 \\error Whatever;199 \\pub fn main() !void {
213 \\pub fn main() %void {
214 \\ const x = unsigned_cast(-10);200 \\ const x = unsigned_cast(-10);
215 \\ if (x == 0) return error.Whatever;201 \\ if (x == 0) return error.Whatever;
216 \\}202 \\}
...@@ -226,20 +212,19 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -226,20 +212,19 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
226 \\ }212 \\ }
227 \\ @import("std").os.exit(0); // test failed213 \\ @import("std").os.exit(0); // test failed
228 \\}214 \\}
229 \\error Whatever;215 \\pub fn main() void {
230 \\pub fn main() %void {
231 \\ bar() catch unreachable;216 \\ bar() catch unreachable;
232 \\}217 \\}
233 \\fn bar() %void {218 \\fn bar() !void {
234 \\ return error.Whatever;219 \\ return error.Whatever;
235 \\}220 \\}
236 );221 );
237222
238 cases.addRuntimeSafety("cast integer to error and no code matches",223 cases.addRuntimeSafety("cast integer to global error and no code matches",
239 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {224 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
240 \\ @import("std").os.exit(126);225 \\ @import("std").os.exit(126);
241 \\}226 \\}
242 \\pub fn main() %void {227 \\pub fn main() void {
243 \\ _ = bar(9999);228 \\ _ = bar(9999);
244 \\}229 \\}
245 \\fn bar(x: u32) error {230 \\fn bar(x: u32) error {
...@@ -247,12 +232,25 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -247,12 +232,25 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
247 \\}232 \\}
248 );233 );
249234
235 cases.addRuntimeSafety("cast integer to non-global error set and no match",
236 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
237 \\ @import("std").os.exit(126);
238 \\}
239 \\const Set1 = error{A, B};
240 \\const Set2 = error{A, C};
241 \\pub fn main() void {
242 \\ _ = foo(Set1.B);
243 \\}
244 \\fn foo(set1: Set1) Set2 {
245 \\ return Set2(set1);
246 \\}
247 );
248
250 cases.addRuntimeSafety("@alignCast misaligned",249 cases.addRuntimeSafety("@alignCast misaligned",
251 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {250 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
252 \\ @import("std").os.exit(126);251 \\ @import("std").os.exit(126);
253 \\}252 \\}
254 \\error Wrong;253 \\pub fn main() !void {
255 \\pub fn main() %void {
256 \\ var array align(4) = []u32{0x11111111, 0x11111111};254 \\ var array align(4) = []u32{0x11111111, 0x11111111};
257 \\ const bytes = ([]u8)(array[0..]);255 \\ const bytes = ([]u8)(array[0..]);
258 \\ if (foo(bytes) != 0x11111111) return error.Wrong;256 \\ if (foo(bytes) != 0x11111111) return error.Wrong;
...@@ -274,7 +272,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -274,7 +272,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
274 \\ int: u32,272 \\ int: u32,
275 \\};273 \\};
276 \\274 \\
277 \\pub fn main() %void {275 \\pub fn main() void {
278 \\ var f = Foo { .int = 42 };276 \\ var f = Foo { .int = 42 };
279 \\ bar(&f);277 \\ bar(&f);
280 \\}278 \\}
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+14-8
...@@ -6,9 +6,6 @@ const assert = debug.assert;...@@ -6,9 +6,6 @@ const assert = debug.assert;
6const Buffer = std.Buffer;6const Buffer = std.Buffer;
7const ArrayList = std.ArrayList;7const ArrayList = std.ArrayList;
88
9error InvalidInput;
10error OutOfMem;
11
12const Token = union(enum) {9const Token = union(enum) {
13 Word: []const u8,10 Word: []const u8,
14 OpenBrace,11 OpenBrace,
...@@ -19,7 +16,7 @@ const Token = union(enum) {...@@ -19,7 +16,7 @@ const Token = union(enum) {
1916
20var global_allocator: &mem.Allocator = undefined;17var global_allocator: &mem.Allocator = undefined;
2118
22fn tokenize(input:[] const u8) %ArrayList(Token) {19fn tokenize(input:[] const u8) !ArrayList(Token) {
23 const State = enum {20 const State = enum {
24 Start,21 Start,
25 Word,22 Word,
...@@ -71,7 +68,12 @@ const Node = union(enum) {...@@ -71,7 +68,12 @@ const Node = union(enum) {
71 Combine: []Node,68 Combine: []Node,
72};69};
7370
74fn 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 {
75 const first_token = tokens.items[*token_index];77 const first_token = tokens.items[*token_index];
76 *token_index += 1;78 *token_index += 1;
7779
...@@ -107,7 +109,7 @@ fn parse(tokens: &const ArrayList(Token), token_index: &usize) %Node {...@@ -107,7 +109,7 @@ fn parse(tokens: &const ArrayList(Token), token_index: &usize) %Node {
107 }109 }
108}110}
109111
110fn expandString(input: []const u8, output: &Buffer) %void {112fn expandString(input: []const u8, output: &Buffer) !void {
111 const tokens = try tokenize(input);113 const tokens = try tokenize(input);
112 if (tokens.len == 1) {114 if (tokens.len == 1) {
113 return output.resize(0);115 return output.resize(0);
...@@ -135,7 +137,11 @@ fn expandString(input: []const u8, output: &Buffer) %void {...@@ -135,7 +137,11 @@ fn expandString(input: []const u8, output: &Buffer) %void {
135 }137 }
136}138}
137139
138fn 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 {
139 assert(output.len == 0);145 assert(output.len == 0);
140 switch (*node) {146 switch (*node) {
141 Node.Scalar => |scalar| {147 Node.Scalar => |scalar| {
...@@ -172,7 +178,7 @@ fn expandNode(node: &const Node, output: &ArrayList(Buffer)) %void {...@@ -172,7 +178,7 @@ fn expandNode(node: &const Node, output: &ArrayList(Buffer)) %void {
172 }178 }
173}179}
174180
175pub fn main() %void {181pub fn main() !void {
176 var stdin_file = try io.getStdIn();182 var stdin_file = try io.getStdIn();
177 var stdout_file = try io.getStdOut();183 var stdout_file = try io.getStdOut();
178184
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");
test/tests.zig+5-8
...@@ -45,9 +45,6 @@ const test_targets = []TestTarget {...@@ -45,9 +45,6 @@ const test_targets = []TestTarget {
45 },45 },
46};46};
4747
48error TestFailed;
49error CompilationIncorrectlySucceeded;
50
51const max_stdout_size = 1 * 1024 * 1024; // 1 MB48const max_stdout_size = 1 * 1024 * 1024; // 1 MB
5249
53pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {50pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
...@@ -248,7 +245,7 @@ pub const CompareOutputContext = struct {...@@ -248,7 +245,7 @@ pub const CompareOutputContext = struct {
248 return ptr;245 return ptr;
249 }246 }
250247
251 fn make(step: &build.Step) %void {248 fn make(step: &build.Step) !void {
252 const self = @fieldParentPtr(RunCompareOutputStep, "step", step);249 const self = @fieldParentPtr(RunCompareOutputStep, "step", step);
253 const b = self.context.b;250 const b = self.context.b;
254251
...@@ -337,7 +334,7 @@ pub const CompareOutputContext = struct {...@@ -337,7 +334,7 @@ pub const CompareOutputContext = struct {
337 return ptr;334 return ptr;
338 }335 }
339336
340 fn make(step: &build.Step) %void {337 fn make(step: &build.Step) !void {
341 const self = @fieldParentPtr(RuntimeSafetyRunStep, "step", step);338 const self = @fieldParentPtr(RuntimeSafetyRunStep, "step", step);
342 const b = self.context.b;339 const b = self.context.b;
343340
...@@ -563,7 +560,7 @@ pub const CompileErrorContext = struct {...@@ -563,7 +560,7 @@ pub const CompileErrorContext = struct {
563 return ptr;560 return ptr;
564 }561 }
565562
566 fn make(step: &build.Step) %void {563 fn make(step: &build.Step) !void {
567 const self = @fieldParentPtr(CompileCmpOutputStep, "step", step);564 const self = @fieldParentPtr(CompileCmpOutputStep, "step", step);
568 const b = self.context.b;565 const b = self.context.b;
569566
...@@ -847,7 +844,7 @@ pub const TranslateCContext = struct {...@@ -847,7 +844,7 @@ pub const TranslateCContext = struct {
847 return ptr;844 return ptr;
848 }845 }
849846
850 fn make(step: &build.Step) %void {847 fn make(step: &build.Step) !void {
851 const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step);848 const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step);
852 const b = self.context.b;849 const b = self.context.b;
853850
...@@ -1045,7 +1042,7 @@ pub const GenHContext = struct {...@@ -1045,7 +1042,7 @@ pub const GenHContext = struct {
1045 return ptr;1042 return ptr;
1046 }1043 }
10471044
1048 fn make(step: &build.Step) %void {1045 fn make(step: &build.Step) !void {
1049 const self = @fieldParentPtr(GenHCmpOutputStep, "step", step);1046 const self = @fieldParentPtr(GenHCmpOutputStep, "step", step);
1050 const b = self.context.b;1047 const b = self.context.b;
10511048