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;
1010const Buffer = std.Buffer;
1111const io = std.io;
1212
13pub fn build(b: &Builder) %void {
13pub fn build(b: &Builder) !void {
1414 const mode = b.standardReleaseOptions();
1515
1616 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
......@@ -149,7 +149,7 @@ const LibraryDep = struct {
149149 includes: ArrayList([]const u8),
150150};
151151
152fn findLLVM(b: &Builder, llvm_config_exe: []const u8) %LibraryDep {
152fn findLLVM(b: &Builder, llvm_config_exe: []const u8) !LibraryDep {
153153 const libs_output = try b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});
154154 const includes_output = try b.exec([][]const u8{llvm_config_exe, "--includedir"});
155155 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%
3030SET "PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%"
3131SET "MSYSTEM=MINGW64"
3232
33bash -lc "pacman -Syu --needed --noconfirm"
34bash -lc "pacman -Su --needed --noconfirm"
33bash -lc "yes | pacman -Syu --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
3838bash -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();
1212const obj_ext = std.build.Target(std.build.Target.Native).oFileExt();
1313const tmp_dir_name = "docgen_tmp";
1414
15pub fn main() %void {
15pub fn main() !void {
1616 // TODO use a more general purpose allocator here
1717 var inc_allocator = try std.heap.IncrementingAllocator.init(max_doc_file_size);
1818 defer inc_allocator.deinit();
......@@ -42,7 +42,7 @@ pub fn main() %void {
4242 const input_file_bytes = try file_in_stream.stream.readAllAlloc(allocator, max_doc_file_size);
4343
4444 var file_out_stream = io.FileOutStream.init(&out_file);
45 var buffered_out_stream = io.BufferedOutStream.init(&file_out_stream.stream);
45 var buffered_out_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream);
4646
4747 var tokenizer = Tokenizer.init(in_file_name, input_file_bytes);
4848 var toc = try genToc(allocator, &tokenizer);
......@@ -218,8 +218,6 @@ const Tokenizer = struct {
218218 }
219219};
220220
221error ParseError;
222
223221fn parseError(tokenizer: &Tokenizer, token: &const Token, comptime fmt: []const u8, args: ...) error {
224222 const loc = tokenizer.getTokenLocation(token);
225223 warn("{}:{}:{}: error: " ++ fmt ++ "\n", tokenizer.source_file_name, loc.line + 1, loc.column + 1, args);
......@@ -243,13 +241,13 @@ fn parseError(tokenizer: &Tokenizer, token: &const Token, comptime fmt: []const
243241 return error.ParseError;
244242}
245243
246fn assertToken(tokenizer: &Tokenizer, token: &const Token, id: Token.Id) %void {
244fn assertToken(tokenizer: &Tokenizer, token: &const Token, id: Token.Id) !void {
247245 if (token.id != id) {
248246 return parseError(tokenizer, token, "expected {}, found {}", @tagName(id), @tagName(token.id));
249247 }
250248}
251249
252fn eatToken(tokenizer: &Tokenizer, id: Token.Id) %Token {
250fn eatToken(tokenizer: &Tokenizer, id: Token.Id) !Token {
253251 const token = tokenizer.next();
254252 try assertToken(tokenizer, token, id);
255253 return token;
......@@ -316,7 +314,7 @@ const Action = enum {
316314 Close,
317315};
318316
319fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) %Toc {
317fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
320318 var urls = std.HashMap([]const u8, Token, mem.hash_slice_u8, mem.eql_slice_u8).init(allocator);
321319 errdefer urls.deinit();
322320
......@@ -540,7 +538,7 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) %Toc {
540538 };
541539}
542540
543fn urlize(allocator: &mem.Allocator, input: []const u8) %[]u8 {
541fn urlize(allocator: &mem.Allocator, input: []const u8) ![]u8 {
544542 var buf = try std.Buffer.initSize(allocator, 0);
545543 defer buf.deinit();
546544
......@@ -560,7 +558,7 @@ fn urlize(allocator: &mem.Allocator, input: []const u8) %[]u8 {
560558 return buf.toOwnedSlice();
561559}
562560
563fn escapeHtml(allocator: &mem.Allocator, input: []const u8) %[]u8 {
561fn escapeHtml(allocator: &mem.Allocator, input: []const u8) ![]u8 {
564562 var buf = try std.Buffer.initSize(allocator, 0);
565563 defer buf.deinit();
566564
......@@ -596,15 +594,13 @@ const TermState = enum {
596594 ExpectEnd,
597595};
598596
599error UnsupportedEscape;
600
601597test "term color" {
602598 const input_bytes = "A\x1b[32;1mgreen\x1b[0mB";
603599 const result = try termColor(std.debug.global_allocator, input_bytes);
604600 assert(mem.eql(u8, result, "A<span class=\"t32\">green</span>B"));
605601}
606602
607fn termColor(allocator: &mem.Allocator, input: []const u8) %[]u8 {
603fn termColor(allocator: &mem.Allocator, input: []const u8) ![]u8 {
608604 var buf = try std.Buffer.initSize(allocator, 0);
609605 defer buf.deinit();
610606
......@@ -684,9 +680,7 @@ fn termColor(allocator: &mem.Allocator, input: []const u8) %[]u8 {
684680 return buf.toOwnedSlice();
685681}
686682
687error ExampleFailedToCompile;
688
689fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io.OutStream, zig_exe: []const u8) %void {
683fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var, zig_exe: []const u8) !void {
690684 var code_progress_index: usize = 0;
691685 for (toc.nodes) |node| {
692686 switch (node) {
......@@ -974,10 +968,7 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io
974968
975969}
976970
977error ChildCrashed;
978error ChildExitError;
979
980fn exec(allocator: &mem.Allocator, args: []const []const u8) %os.ChildProcess.ExecResult {
971fn exec(allocator: &mem.Allocator, args: []const []const u8) !os.ChildProcess.ExecResult {
981972 const result = try os.ChildProcess.exec(allocator, args, null, null, max_doc_file_size);
982973 switch (result.term) {
983974 os.ChildProcess.Term.Exited => |exit_code| {
doc/langref.html.in+62-76
......@@ -108,7 +108,7 @@
108108 {#code_begin|exe|hello#}
109109const std = @import("std");
110110
111pub fn main() %void {
111pub fn main() !void {
112112 // If this program is run without stdout attached, exit with an error.
113113 var stdout_file = try std.io.getStdOut();
114114 // If this program encounters pipe failure when printing to stdout, exit
......@@ -129,8 +129,8 @@ pub fn main() void {
129129}
130130 {#code_end#}
131131 <p>
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.
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 must use the <code class="zig">void</code> return type.
134134 </p>
135135 {#see_also|Values|@import|Errors|Root Source File#}
136136 {#header_close#}
......@@ -141,10 +141,7 @@ const warn = std.debug.warn;
141141const os = std.os;
142142const assert = std.debug.assert;
143143
144// error declaration, makes `error.ArgNotFound` available
145error ArgNotFound;
146
147pub fn main() %void {
144pub fn main() void {
148145 // integers
149146 const one_plus_one: i32 = 1 + 1;
150147 warn("1 + 1 = {}\n", one_plus_one);
......@@ -173,7 +170,7 @@ pub fn main() %void {
173170 @typeName(@typeOf(nullable_value)), nullable_value);
174171
175172 // error union
176 var number_or_error: %i32 = error.ArgNotFound;
173 var number_or_error: error!i32 = error.ArgNotFound;
177174
178175 warn("\nerror union 1\ntype: {}\nvalue: {}\n",
179176 @typeName(@typeOf(number_or_error)), number_or_error);
......@@ -681,7 +678,7 @@ const warn = @import("std").debug.warn;
681678extern fn foo_strict(x: f64) f64;
682679extern fn foo_optimized(x: f64) f64;
683680
684pub fn main() %void {
681pub fn main() void {
685682 const x = 0.001;
686683 warn("optimized = {}\n", foo_optimized(x));
687684 warn("strict = {}\n", foo_strict(x));
......@@ -1036,7 +1033,7 @@ a catch |err| b</code></pre></td>
10361033 <code>err</code> is the <code>error</code> and is in scope of the expression <code>b</code>.
10371034 </td>
10381035 <td>
1039 <pre><code class="zig">const value: %u32 = null;
1036 <pre><code class="zig">const value: error!u32 = error.Broken;
10401037const unwrapped = value catch 1234;
10411038unwrapped == 1234</code></pre>
10421039 </td>
......@@ -1269,9 +1266,10 @@ const ptr = &amp;x;
12691266 {#header_close#}
12701267 {#header_open|Precedence#}
12711268 <pre><code>x() x[] x.y
1272!x -x -%x ~x *x &amp;x ?x %x ??x
1269a!b
1270!x -x -%x ~x *x &amp;x ?x ??x
12731271x{}
1274* / % ** *%
1272! * / % ** *%
12751273+ - ++ +% -%
12761274&lt;&lt; &gt;&gt;
12771275&amp;
......@@ -2268,8 +2266,8 @@ fn eventuallyNullSequence() ?u32 {
22682266 break :blk numbers_left;
22692267 };
22702268}
2271error ReachedZero;
2272fn eventuallyErrorSequence() %u32 {
2269
2270fn eventuallyErrorSequence() error!u32 {
22732271 return if (numbers_left == 0) error.ReachedZero else blk: {
22742272 numbers_left -= 1;
22752273 break :blk numbers_left;
......@@ -2398,7 +2396,7 @@ fn typeNameLength(comptime T: type) usize {
23982396// If expressions have three uses, corresponding to the three types:
23992397// * bool
24002398// * ?T
2401// * %T
2399// * error!T
24022400
24032401const assert = @import("std").debug.assert;
24042402
......@@ -2459,20 +2457,18 @@ test "if nullable" {
24592457 }
24602458}
24612459
2462error BadValue;
2463error LessBadValue;
24642460test "if error union" {
24652461 // If expressions test for errors.
24662462 // Note the |err| capture on the else.
24672463
2468 const a: %u32 = 0;
2464 const a: error!u32 = 0;
24692465 if (a) |value| {
24702466 assert(value == 0);
24712467 } else |err| {
24722468 unreachable;
24732469 }
24742470
2475 const b: %u32 = error.BadValue;
2471 const b: error!u32 = error.BadValue;
24762472 if (b) |value| {
24772473 unreachable;
24782474 } else |err| {
......@@ -2490,7 +2486,7 @@ test "if error union" {
24902486 }
24912487
24922488 // Access the value by reference using a pointer capture.
2493 var c: %u32 = 3;
2489 var c: error!u32 = 3;
24942490 if (c) |*value| {
24952491 *value = 9;
24962492 } else |err| {
......@@ -2558,8 +2554,7 @@ test "defer unwinding" {
25582554//
25592555// This is especially useful in allowing a function to clean up properly
25602556// on error, and replaces goto error handling tactics as seen in c.
2561error DeferError;
2562fn deferErrorExample(is_error: bool) %void {
2557fn deferErrorExample(is_error: bool) !void {
25632558 warn("\nstart of function\n");
25642559
25652560 // This will always be executed on exit
......@@ -2668,7 +2663,7 @@ test "foo" {
26682663 assert(value == 1234);
26692664}
26702665
2671fn bar() %u32 {
2666fn bar() error!u32 {
26722667 return 1234;
26732668}
26742669
......@@ -2791,13 +2786,8 @@ test "fn reflection" {
27912786 One of the distinguishing features of Zig is its exception handling strategy.
27922787 </p>
27932788 <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
27952790 </p>
2796 {#code_begin|syntax#}
2797error FileNotFound;
2798error OutOfMemory;
2799error UnexpectedToken;
2800 {#code_end#}
28012791 <p>
28022792 These error values are assigned an unsigned integer value greater than 0 at
28032793 compile time. You are allowed to declare the same error value more than once,
......@@ -2809,26 +2799,23 @@ error UnexpectedToken;
28092799 </p>
28102800 <p>
28112801 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.
28132803 </p>
28142804 <p>
2815 The pure error 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.
2805 The error set type is one of the error values, and in the same way that pointers
2806 cannot be null, a error set instance is always an error.
28172807 </p>
28182808 {#code_begin|syntax#}const pure_error = error.FileNotFound;{#code_end#}
28192809 <p>
2820 Most of the time you will not find yourself using a pure error type. Instead,
2821 likely you will be using the error union type. This is when you take a normal type,
2822 and prefix it with the <code>%</code> operator.
2810 Most of the time you will not find yourself using an error set type. Instead,
2811 likely you will be using the error union type. This is when you take an error set
2812 and a normal type, and create an error union with the <code>!</code> binary operator.
28232813 </p>
28242814 <p>
28252815 Here is a function to parse a string into a 64-bit integer:
28262816 </p>
28272817 {#code_begin|test#}
2828error InvalidChar;
2829error Overflow;
2830
2831pub fn parseU64(buf: []const u8, radix: u8) %u64 {
2818pub fn parseU64(buf: []const u8, radix: u8) !u64 {
28322819 var x: u64 = 0;
28332820
28342821 for (buf) |c| {
......@@ -2867,13 +2854,14 @@ test "parse u64" {
28672854}
28682855 {#code_end#}
28692856 <p>
2870 Notice the return type is <code>%u64</code>. This means that the function
2871 either returns an unsigned 64 bit integer, or an error.
2857 Notice the return type is <code>!u64</code>. This means that the function
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.
28722860 </p>
28732861 <p>
28742862 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>.
2876 Both types implicitly cast to <code>%u64</code>.
2863 an error, and at the bottom a return statement that returns a <code>u64</code>.
2864 Both types implicitly cast to <code>error!u64</code>.
28772865 </p>
28782866 <p>
28792867 What it looks like to use this function varies depending on what you're
......@@ -2900,7 +2888,7 @@ fn doAThing(str: []u8) void {
29002888 <p>Let's say you wanted to return the error if you got one, otherwise continue with the
29012889 function logic:</p>
29022890 {#code_begin|syntax#}
2903fn doAThing(str: []u8) %void {
2891fn doAThing(str: []u8) !void {
29042892 const number = parseU64(str, 10) catch |err| return err;
29052893 // ...
29062894}
......@@ -2909,7 +2897,7 @@ fn doAThing(str: []u8) %void {
29092897 There is a shortcut for this. The <code>try</code> expression:
29102898 </p>
29112899 {#code_begin|syntax#}
2912fn doAThing(str: []u8) %void {
2900fn doAThing(str: []u8) !void {
29132901 const number = try parseU64(str, 10);
29142902 // ...
29152903}
......@@ -2959,7 +2947,7 @@ fn doAThing(str: []u8) void {
29592947 Example:
29602948 </p>
29612949 {#code_begin|syntax#}
2962fn createFoo(param: i32) %Foo {
2950fn createFoo(param: i32) !Foo {
29632951 const foo = try tryToAllocateFoo();
29642952 // now we have allocated foo. we need to free it if the function fails.
29652953 // but we want to return it if the function succeeds.
......@@ -2999,15 +2987,13 @@ fn createFoo(param: i32) %Foo {
29992987 </ul>
30002988 {#see_also|defer|if|switch#}
30012989 {#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.
30032991 You can use compile-time reflection to access the child type of an error union:</p>
30042992 {#code_begin|test#}
30052993const assert = @import("std").debug.assert;
30062994
3007error SomeError;
3008
30092995test "error union" {
3010 var foo: %i32 = undefined;
2996 var foo: error!i32 = undefined;
30112997
30122998 // Implicitly cast from child type of an error union:
30132999 foo = 1234;
......@@ -3015,8 +3001,11 @@ test "error union" {
30153001 // Implicitly cast from an error set:
30163002 foo = error.SomeError;
30173003
3018 // Use compile-time reflection to access the child type of an error union:
3019 comptime assert(@typeOf(foo).Child == i32);
3004 // Use compile-time reflection to access the payload type of an error union:
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);
30203009}
30213010 {#code_end#}
30223011 {#header_close#}
......@@ -3610,7 +3599,7 @@ pub fn main() void {
36103599
36113600 {#code_begin|syntax#}
36123601/// 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 {
36143603 const State = enum {
36153604 Start,
36163605 OpenBrace,
......@@ -3682,7 +3671,7 @@ pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) %void {
36823671 and emits a function that actually looks like this:
36833672 </p>
36843673 {#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 {
36863675 try self.write("here is a string: '");
36873676 try self.printValue(arg0);
36883677 try self.write("' here is a number: ");
......@@ -3696,7 +3685,7 @@ pub fn printf(self: &OutStream, arg0: i32, arg1: []const u8) %void {
36963685 on the type:
36973686 </p>
36983687 {#code_begin|syntax#}
3699pub fn printValue(self: &OutStream, value: var) %void {
3688pub fn printValue(self: &OutStream, value: var) !void {
37003689 const T = @typeOf(value);
37013690 if (@isInteger(T)) {
37023691 return self.printInt(T, value);
......@@ -4647,7 +4636,7 @@ pub const TypeId = enum {
46474636 {#code_begin|syntax#}
46484637const Builder = @import("std").build.Builder;
46494638
4650pub fn build(b: &Builder) %void {
4639pub fn build(b: &Builder) void {
46514640 const exe = b.addExecutable("example", "example.zig");
46524641 exe.setBuildMode(b.standardReleaseOptions());
46534642 b.default_step.dependOn(&exe.step);
......@@ -4789,7 +4778,7 @@ comptime {
47894778 {#code_begin|exe_err#}
47904779const math = @import("std").math;
47914780const warn = @import("std").debug.warn;
4792pub fn main() %void {
4781pub fn main() !void {
47934782 var byte: u8 = 255;
47944783
47954784 byte = if (math.add(u8, byte, 1)) |result| result else |err| {
......@@ -4817,7 +4806,7 @@ pub fn main() %void {
48174806 </p>
48184807 {#code_begin|exe#}
48194808const warn = @import("std").debug.warn;
4820pub fn main() %void {
4809pub fn main() void {
48214810 var byte: u8 = 255;
48224811
48234812 var result: u8 = undefined;
......@@ -4926,14 +4915,12 @@ pub fn main() void {
49264915 {#header_close#}
49274916 {#header_open|Attempt to Unwrap Error#}
49284917 <p>At compile-time:</p>
4929 {#code_begin|test_err|unable to unwrap error 'UnableToReturnNumber'#}
4918 {#code_begin|test_err|caught unexpected error 'UnableToReturnNumber'#}
49304919comptime {
49314920 const number = getNumberOrFail() catch unreachable;
49324921}
49334922
4934error UnableToReturnNumber;
4935
4936fn getNumberOrFail() %i32 {
4923fn getNumberOrFail() !i32 {
49374924 return error.UnableToReturnNumber;
49384925}
49394926 {#code_end#}
......@@ -4953,9 +4940,7 @@ pub fn main() void {
49534940 }
49544941}
49554942
4956error UnableToReturnNumber;
4957
4958fn getNumberOrFail() %i32 {
4943fn getNumberOrFail() !i32 {
49594944 return error.UnableToReturnNumber;
49604945}
49614946 {#code_end#}
......@@ -4963,7 +4948,6 @@ fn getNumberOrFail() %i32 {
49634948 {#header_open|Invalid Error Code#}
49644949 <p>At compile-time:</p>
49654950 {#code_begin|test_err|integer value 11 represents no error#}
4966error AnError;
49674951comptime {
49684952 const err = error.AnError;
49694953 const number = u32(err) + 10;
......@@ -5363,7 +5347,7 @@ int main(int argc, char **argv) {
53635347 {#code_begin|syntax#}
53645348const Builder = @import("std").build.Builder;
53655349
5366pub fn build(b: &Builder) %void {
5350pub fn build(b: &Builder) void {
53675351 const obj = b.addObject("base64", "base64.zig");
53685352
53695353 const exe = b.addCExecutable("test");
......@@ -5641,14 +5625,12 @@ fn readU32Be() u32 {}
56415625 {#header_open|Grammar#}
56425626 <pre><code class="nohighlight">Root = many(TopLevelItem) EOF
56435627
5644TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestDecl
5628TopLevelItem = CompTimeExpression(Block) | TopLevelDecl | TestDecl
56455629
56465630TestDecl = "test" String Block
56475631
56485632TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl)
56495633
5650ErrorValueDecl = "error" Symbol ";"
5651
56525634GlobalVarDecl = option("export") VariableDeclaration ";"
56535635
56545636LocalVarDecl = option("comptime") VariableDeclaration
......@@ -5663,7 +5645,7 @@ UseDecl = "use" Expression ";"
56635645
56645646ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"
56655647
5666FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") TypeExpr
5648FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
56675649
56685650FnDef = option("inline" | "export") FnProto Block
56695651
......@@ -5675,7 +5657,9 @@ Block = option(Symbol ":") "{" many(Statement) "}"
56755657
56765658Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
56775659
5678TypeExpr = PrefixOpExpression | "var"
5660TypeExpr = ErrorSetExpr | "var"
5661
5662ErrorSetExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression
56795663
56805664BlockOrExpression = Block | Expression
56815665
......@@ -5757,9 +5741,9 @@ MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression |
57575741
57585742CurlySuffixExpression = TypeExpr option(ContainerInitExpression)
57595743
5760MultiplyOperator = "*" | "/" | "%" | "**" | "*%"
5744MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
57615745
5762PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression
5746PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression
57635747
57645748SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
57655749
......@@ -5777,9 +5761,9 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",")
57775761
57785762StructLiteralField = "." 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
57845768ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr
57855769
......@@ -5787,6 +5771,8 @@ GroupedExpression = "(" Expression ")"
57875771
57885772KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable"
57895773
5774ErrorSetDecl = "error" "{" list(Symbol, ",") "}"
5775
57905776ContainerDecl = option("extern" | "packed")
57915777 ("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression)))
57925778 "{" many(ContainerMember) "}"</code></pre>
example/cat/main.zig+4-4
......@@ -5,7 +5,7 @@ const os = std.os;
55const warn = std.debug.warn;
66const allocator = std.debug.global_allocator;
77
8pub fn main() %void {
8pub fn main() !void {
99 var args_it = os.args();
1010 const exe = try unwrapArg(??args_it.next(allocator));
1111 var catted_anything = false;
......@@ -36,12 +36,12 @@ pub fn main() %void {
3636 }
3737}
3838
39fn usage(exe: []const u8) %void {
39fn usage(exe: []const u8) !void {
4040 warn("Usage: {} [FILE]...\n", exe);
4141 return error.Invalid;
4242}
4343
44fn cat_file(stdout: &io.File, file: &io.File) %void {
44fn cat_file(stdout: &io.File, file: &io.File) !void {
4545 var buf: [1024 * 4]u8 = undefined;
4646
4747 while (true) {
......@@ -61,7 +61,7 @@ fn cat_file(stdout: &io.File, file: &io.File) %void {
6161 }
6262}
6363
64fn unwrapArg(arg: %[]u8) %[]u8 {
64fn unwrapArg(arg: error![]u8) ![]u8 {
6565 return arg catch |err| {
6666 warn("Unable to parse command line: {}\n", err);
6767 return err;
example/guess_number/main.zig+1-1
......@@ -5,7 +5,7 @@ const fmt = std.fmt;
55const Rand = std.rand.Rand;
66const os = std.os;
77
8pub fn main() %void {
8pub fn main() !void {
99 var stdout_file = try io.getStdOut();
1010 var stdout_file_stream = io.FileOutStream.init(&stdout_file);
1111 const stdout = &stdout_file_stream.stream;
example/hello_world/hello.zig+1-1
......@@ -1,6 +1,6 @@
11const std = @import("std");
22
3pub fn main() %void {
3pub fn main() !void {
44 // If this program is run without stdout attached, exit with an error.
55 var stdout_file = try std.io.getStdOut();
66 // If this program encounters pipe failure when printing to stdout, exit
example/mix_o_files/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) %void {
3pub fn build(b: &Builder) void {
44 const obj = b.addObject("base64", "base64.zig");
55
66 const exe = b.addCExecutable("test");
example/shared_library/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) %void {
3pub fn build(b: &Builder) void {
44 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
55
66 const exe = b.addCExecutable("test");
src-self-hosted/main.zig+7-11
......@@ -14,13 +14,9 @@ const builtin = @import("builtin");
1414const ArrayList = std.ArrayList;
1515const c = @import("c.zig");
1616
17error InvalidCommandLineArguments;
18error ZigLibDirNotFound;
19error ZigInstallationNotFound;
20
2117const default_zig_cache_name = "zig-cache";
2218
23pub fn main() %void {
19pub fn main() !void {
2420 main2() catch |err| {
2521 if (err != error.InvalidCommandLineArguments) {
2622 warn("{}\n", @errorName(err));
......@@ -48,7 +44,7 @@ fn badArgs(comptime format: []const u8, args: ...) error {
4844 return error.InvalidCommandLineArguments;
4945}
5046
51pub fn main2() %void {
47pub fn main2() !void {
5248 const allocator = std.heap.c_allocator;
5349
5450 const args = try os.argsAlloc(allocator);
......@@ -472,7 +468,7 @@ pub fn main2() %void {
472468 }
473469}
474470
475fn printUsage(stream: &io.OutStream) %void {
471fn printUsage(stream: var) !void {
476472 try stream.write(
477473 \\Usage: zig [command] [options]
478474 \\
......@@ -548,7 +544,7 @@ fn printUsage(stream: &io.OutStream) %void {
548544 );
549545}
550546
551fn printZen() %void {
547fn printZen() !void {
552548 var stdout_file = try io.getStdErr();
553549 try stdout_file.write(
554550 \\
......@@ -569,7 +565,7 @@ fn printZen() %void {
569565}
570566
571567/// 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 {
573569 if (zig_install_prefix_arg) |zig_install_prefix| {
574570 return testZigInstallPrefix(allocator, zig_install_prefix) catch |err| {
575571 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
585581}
586582
587583/// Caller must free result
588fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) %[]u8 {
584fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) ![]u8 {
589585 const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig");
590586 errdefer allocator.free(test_zig_dir);
591587
......@@ -599,7 +595,7 @@ fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) %[]u8
599595}
600596
601597/// Caller must free result
602fn findZigLibDir(allocator: &mem.Allocator) %[]u8 {
598fn findZigLibDir(allocator: &mem.Allocator) ![]u8 {
603599 const self_exe_path = try os.selfExeDirPath(allocator);
604600 defer allocator.free(self_exe_path);
605601
src-self-hosted/module.zig+6-5
......@@ -110,7 +110,7 @@ pub const Module = struct {
110110 };
111111
112112 pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target,
113 kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) %&Module
113 kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !&Module
114114 {
115115 var name_buffer = try Buffer.init(allocator, name);
116116 errdefer name_buffer.deinit();
......@@ -198,7 +198,7 @@ pub const Module = struct {
198198 self.allocator.destroy(self);
199199 }
200200
201 pub fn build(self: &Module) %void {
201 pub fn build(self: &Module) !void {
202202 if (self.llvm_argv.len != 0) {
203203 var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.allocator,
204204 [][]const []const u8 { [][]const u8{"zig (LLVM option parsing)"}, self.llvm_argv, });
......@@ -263,11 +263,12 @@ pub const Module = struct {
263263
264264 }
265265
266 pub fn link(self: &Module, out_file: ?[]const u8) %void {
266 pub fn link(self: &Module, out_file: ?[]const u8) !void {
267267 warn("TODO link");
268 return error.Todo;
268269 }
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 {
271272 const is_libc = mem.eql(u8, name, "c");
272273
273274 if (is_libc) {
......@@ -297,7 +298,7 @@ pub const Module = struct {
297298 }
298299};
299300
300fn printError(comptime format: []const u8, args: ...) %void {
301fn printError(comptime format: []const u8, args: ...) !void {
301302 var stderr_file = try std.io.getStdErr();
302303 var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);
303304 const out_stream = &stderr_file_out_stream.stream;
src-self-hosted/parser.zig+22-28
......@@ -12,8 +12,6 @@ const io = std.io;
1212// get rid of this
1313const warn = std.debug.warn;
1414
15error ParseError;
16
1715pub const Parser = struct {
1816 allocator: &mem.Allocator,
1917 tokenizer: &Tokenizer,
......@@ -63,7 +61,7 @@ pub const Parser = struct {
6361 NullableField: &?&ast.Node,
6462 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 {
6765 switch (*self) {
6866 DestPtr.Field => |ptr| *ptr = value,
6967 DestPtr.NullableField => |ptr| *ptr = value,
......@@ -99,7 +97,7 @@ pub const Parser = struct {
9997
10098 /// Returns an AST tree, allocated with the parser's allocator.
10199 /// Result should be freed with `freeAst` when done.
102 pub fn parse(self: &Parser) %Tree {
100 pub fn parse(self: &Parser) !Tree {
103101 var stack = self.initUtilityArrayList(State);
104102 defer self.deinitUtilityArrayList(stack);
105103
......@@ -544,7 +542,7 @@ pub const Parser = struct {
544542 }
545543 }
546544
547 fn createRoot(self: &Parser) %&ast.NodeRoot {
545 fn createRoot(self: &Parser) !&ast.NodeRoot {
548546 const node = try self.allocator.create(ast.NodeRoot);
549547
550548 *node = ast.NodeRoot {
......@@ -555,7 +553,7 @@ pub const Parser = struct {
555553 }
556554
557555 fn createVarDecl(self: &Parser, visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token,
558 extern_token: &const ?Token) %&ast.NodeVarDecl
556 extern_token: &const ?Token) !&ast.NodeVarDecl
559557 {
560558 const node = try self.allocator.create(ast.NodeVarDecl);
561559
......@@ -577,7 +575,7 @@ pub const Parser = struct {
577575 }
578576
579577 fn createFnProto(self: &Parser, fn_token: &const Token, extern_token: &const ?Token,
580 cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) %&ast.NodeFnProto
578 cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) !&ast.NodeFnProto
581579 {
582580 const node = try self.allocator.create(ast.NodeFnProto);
583581
......@@ -599,7 +597,7 @@ pub const Parser = struct {
599597 return node;
600598 }
601599
602 fn createParamDecl(self: &Parser) %&ast.NodeParamDecl {
600 fn createParamDecl(self: &Parser) !&ast.NodeParamDecl {
603601 const node = try self.allocator.create(ast.NodeParamDecl);
604602
605603 *node = ast.NodeParamDecl {
......@@ -613,7 +611,7 @@ pub const Parser = struct {
613611 return node;
614612 }
615613
616 fn createBlock(self: &Parser, begin_token: &const Token) %&ast.NodeBlock {
614 fn createBlock(self: &Parser, begin_token: &const Token) !&ast.NodeBlock {
617615 const node = try self.allocator.create(ast.NodeBlock);
618616
619617 *node = ast.NodeBlock {
......@@ -625,7 +623,7 @@ pub const Parser = struct {
625623 return node;
626624 }
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 {
629627 const node = try self.allocator.create(ast.NodeInfixOp);
630628
631629 *node = ast.NodeInfixOp {
......@@ -638,7 +636,7 @@ pub const Parser = struct {
638636 return node;
639637 }
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 {
642640 const node = try self.allocator.create(ast.NodePrefixOp);
643641
644642 *node = ast.NodePrefixOp {
......@@ -650,7 +648,7 @@ pub const Parser = struct {
650648 return node;
651649 }
652650
653 fn createIdentifier(self: &Parser, name_token: &const Token) %&ast.NodeIdentifier {
651 fn createIdentifier(self: &Parser, name_token: &const Token) !&ast.NodeIdentifier {
654652 const node = try self.allocator.create(ast.NodeIdentifier);
655653
656654 *node = ast.NodeIdentifier {
......@@ -660,7 +658,7 @@ pub const Parser = struct {
660658 return node;
661659 }
662660
663 fn createIntegerLiteral(self: &Parser, token: &const Token) %&ast.NodeIntegerLiteral {
661 fn createIntegerLiteral(self: &Parser, token: &const Token) !&ast.NodeIntegerLiteral {
664662 const node = try self.allocator.create(ast.NodeIntegerLiteral);
665663
666664 *node = ast.NodeIntegerLiteral {
......@@ -670,7 +668,7 @@ pub const Parser = struct {
670668 return node;
671669 }
672670
673 fn createFloatLiteral(self: &Parser, token: &const Token) %&ast.NodeFloatLiteral {
671 fn createFloatLiteral(self: &Parser, token: &const Token) !&ast.NodeFloatLiteral {
674672 const node = try self.allocator.create(ast.NodeFloatLiteral);
675673
676674 *node = ast.NodeFloatLiteral {
......@@ -680,13 +678,13 @@ pub const Parser = struct {
680678 return node;
681679 }
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 {
684682 const node = try self.createIdentifier(name_token);
685683 try dest_ptr.store(&node.base);
686684 return node;
687685 }
688686
689 fn createAttachParamDecl(self: &Parser, list: &ArrayList(&ast.Node)) %&ast.NodeParamDecl {
687 fn createAttachParamDecl(self: &Parser, list: &ArrayList(&ast.Node)) !&ast.NodeParamDecl {
690688 const node = try self.createParamDecl();
691689 try list.append(&node.base);
692690 return node;
......@@ -694,7 +692,7 @@ pub const Parser = struct {
694692
695693 fn createAttachFnProto(self: &Parser, list: &ArrayList(&ast.Node), fn_token: &const Token,
696694 extern_token: &const ?Token, cc_token: &const ?Token, visib_token: &const ?Token,
697 inline_token: &const ?Token) %&ast.NodeFnProto
695 inline_token: &const ?Token) !&ast.NodeFnProto
698696 {
699697 const node = try self.createFnProto(fn_token, extern_token, cc_token, visib_token, inline_token);
700698 try list.append(&node.base);
......@@ -702,7 +700,7 @@ pub const Parser = struct {
702700 }
703701
704702 fn createAttachVarDecl(self: &Parser, list: &ArrayList(&ast.Node), visib_token: &const ?Token,
705 mut_token: &const Token, comptime_token: &const ?Token, extern_token: &const ?Token) %&ast.NodeVarDecl
703 mut_token: &const Token, comptime_token: &const ?Token, extern_token: &const ?Token) !&ast.NodeVarDecl
706704 {
707705 const node = try self.createVarDecl(visib_token, mut_token, comptime_token, extern_token);
708706 try list.append(&node.base);
......@@ -730,13 +728,13 @@ pub const Parser = struct {
730728 return error.ParseError;
731729 }
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 {
734732 if (token.id != id) {
735733 return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id));
736734 }
737735 }
738736
739 fn eatToken(self: &Parser, id: @TagType(Token.Id)) %Token {
737 fn eatToken(self: &Parser, id: @TagType(Token.Id)) !Token {
740738 const token = self.getNextToken();
741739 try self.expectToken(token, id);
742740 return token;
......@@ -763,7 +761,7 @@ pub const Parser = struct {
763761 indent: usize,
764762 };
765763
766 pub fn renderAst(self: &Parser, stream: &std.io.OutStream, root_node: &ast.NodeRoot) %void {
764 pub fn renderAst(self: &Parser, stream: var, root_node: &ast.NodeRoot) !void {
767765 var stack = self.initUtilityArrayList(RenderAstFrame);
768766 defer self.deinitUtilityArrayList(stack);
769767
......@@ -802,7 +800,7 @@ pub const Parser = struct {
802800 Indent: usize,
803801 };
804802
805 pub fn renderSource(self: &Parser, stream: &std.io.OutStream, root_node: &ast.NodeRoot) %void {
803 pub fn renderSource(self: &Parser, stream: var, root_node: &ast.NodeRoot) !void {
806804 var stack = self.initUtilityArrayList(RenderState);
807805 defer self.deinitUtilityArrayList(stack);
808806
......@@ -1038,7 +1036,7 @@ pub const Parser = struct {
10381036
10391037var 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 {
10421040 var padded_source: [0x100]u8 = undefined;
10431041 std.mem.copy(u8, padded_source[0..source.len], source);
10441042 padded_source[source.len + 0] = '\n';
......@@ -1058,13 +1056,9 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) %[]u8 {
10581056 return buffer.toOwnedSlice();
10591057}
10601058
1061error TestFailed;
1062error NondeterministicMemoryUsage;
1063error MemoryLeakDetected;
1064
10651059// TODO test for memory leaks
10661060// TODO test for valid frees
1067fn testCanonical(source: []const u8) %void {
1061fn testCanonical(source: []const u8) !void {
10681062 const needed_alloc_count = x: {
10691063 // Try it once with unlimited memory, make sure it works
10701064 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
src/all_types.hpp+47-21
......@@ -236,7 +236,7 @@ struct ConstExprValue {
236236 TypeTableEntry *x_type;
237237 ConstExprValue *x_maybe;
238238 ConstErrValue x_err_union;
239 ErrorTableEntry *x_pure_err;
239 ErrorTableEntry *x_err_set;
240240 BigInt x_enum_tag;
241241 ConstStructValue x_struct;
242242 ConstUnionValue x_union;
......@@ -353,7 +353,6 @@ enum NodeType {
353353 NodeTypeReturnExpr,
354354 NodeTypeDefer,
355355 NodeTypeVariableDeclaration,
356 NodeTypeErrorValueDecl,
357356 NodeTypeTestDecl,
358357 NodeTypeBinOpExpr,
359358 NodeTypeUnwrapErrorExpr,
......@@ -393,6 +392,7 @@ enum NodeType {
393392 NodeTypeVarLiteral,
394393 NodeTypeIfErrorExpr,
395394 NodeTypeTestExpr,
395 NodeTypeErrorSetDecl,
396396};
397397
398398struct AstNodeRoot {
......@@ -424,6 +424,8 @@ struct AstNodeFnProto {
424424 AstNode *align_expr;
425425 // populated if the "section(S)" is present
426426 AstNode *section_expr;
427
428 bool auto_err_set;
427429};
428430
429431struct AstNodeFnDef {
......@@ -486,12 +488,6 @@ struct AstNodeVariableDeclaration {
486488 AstNode *section_expr;
487489};
488490
489struct AstNodeErrorValueDecl {
490 Buf *name;
491
492 ErrorTableEntry *err;
493};
494
495491struct AstNodeTestDecl {
496492 Buf *name;
497493
......@@ -514,8 +510,7 @@ enum BinOpType {
514510 BinOpTypeAssignBitAnd,
515511 BinOpTypeAssignBitXor,
516512 BinOpTypeAssignBitOr,
517 BinOpTypeAssignBoolAnd,
518 BinOpTypeAssignBoolOr,
513 BinOpTypeAssignMergeErrorSets,
519514 BinOpTypeBoolOr,
520515 BinOpTypeBoolAnd,
521516 BinOpTypeCmpEq,
......@@ -540,6 +535,8 @@ enum BinOpType {
540535 BinOpTypeUnwrapMaybe,
541536 BinOpTypeArrayCat,
542537 BinOpTypeArrayMult,
538 BinOpTypeErrorUnion,
539 BinOpTypeMergeErrorSets,
543540};
544541
545542struct AstNodeBinOpExpr {
......@@ -563,6 +560,7 @@ enum CastOp {
563560 CastOpResizeSlice,
564561 CastOpBytesToSlice,
565562 CastOpNumLitToConcrete,
563 CastOpErrSet,
566564};
567565
568566struct AstNodeFnCallExpr {
......@@ -595,7 +593,6 @@ enum PrefixOp {
595593 PrefixOpNegationWrap,
596594 PrefixOpDereference,
597595 PrefixOpMaybe,
598 PrefixOpError,
599596 PrefixOpUnwrapMaybe,
600597};
601598
......@@ -762,6 +759,10 @@ struct AstNodeContainerDecl {
762759 bool auto_enum; // union(enum)
763760};
764761
762struct AstNodeErrorSetDecl {
763 ZigList<AstNode *> decls;
764};
765
765766struct AstNodeStructField {
766767 VisibMod visib_mod;
767768 Buf *name;
......@@ -858,7 +859,6 @@ struct AstNode {
858859 AstNodeReturnExpr return_expr;
859860 AstNodeDefer defer;
860861 AstNodeVariableDeclaration variable_declaration;
861 AstNodeErrorValueDecl error_value_decl;
862862 AstNodeTestDecl test_decl;
863863 AstNodeBinOpExpr bin_op_expr;
864864 AstNodeCatchExpr unwrap_err_expr;
......@@ -899,6 +899,7 @@ struct AstNode {
899899 AstNodeArrayType array_type;
900900 AstNodeErrorType error_type;
901901 AstNodeVarLiteral var_literal;
902 AstNodeErrorSetDecl err_set_decl;
902903 } data;
903904};
904905
......@@ -993,8 +994,15 @@ struct TypeTableEntryMaybe {
993994 TypeTableEntry *child_type;
994995};
995996
996struct TypeTableEntryError {
997 TypeTableEntry *child_type;
997struct TypeTableEntryErrorUnion {
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;
9981006};
9991007
10001008struct TypeTableEntryEnum {
......@@ -1097,7 +1105,7 @@ enum TypeTableEntryId {
10971105 TypeTableEntryIdNullLit,
10981106 TypeTableEntryIdMaybe,
10991107 TypeTableEntryIdErrorUnion,
1100 TypeTableEntryIdPureError,
1108 TypeTableEntryIdErrorSet,
11011109 TypeTableEntryIdEnum,
11021110 TypeTableEntryIdUnion,
11031111 TypeTableEntryIdFn,
......@@ -1126,7 +1134,8 @@ struct TypeTableEntry {
11261134 TypeTableEntryArray array;
11271135 TypeTableEntryStruct structure;
11281136 TypeTableEntryMaybe maybe;
1129 TypeTableEntryError error;
1137 TypeTableEntryErrorUnion error_union;
1138 TypeTableEntryErrorSet error_set;
11301139 TypeTableEntryEnum enumeration;
11311140 TypeTableEntryUnion unionation;
11321141 TypeTableEntryFn fn;
......@@ -1136,7 +1145,6 @@ struct TypeTableEntry {
11361145 // use these fields to make sure we don't duplicate type table entries for the same type
11371146 TypeTableEntry *pointer_parent[2]; // [0 - mut, 1 - const]
11381147 TypeTableEntry *maybe_parent;
1139 TypeTableEntry *error_parent;
11401148 // If we generate a constant name value for this type, we memoize it here.
11411149 // The type of this is array
11421150 ConstExprValue *cached_const_name_val;
......@@ -1340,6 +1348,10 @@ struct TypeId {
13401348 bool is_signed;
13411349 uint32_t bit_count;
13421350 } integer;
1351 struct {
1352 TypeTableEntry *err_set_type;
1353 TypeTableEntry *payload_type;
1354 } error_union;
13431355 } data;
13441356};
13451357
......@@ -1481,7 +1493,7 @@ struct CodeGen {
14811493 TypeTableEntry *entry_undef;
14821494 TypeTableEntry *entry_null;
14831495 TypeTableEntry *entry_var;
1484 TypeTableEntry *entry_pure_error;
1496 TypeTableEntry *entry_global_error_set;
14851497 TypeTableEntry *entry_arg_tuple;
14861498 } builtin_types;
14871499
......@@ -1570,7 +1582,6 @@ struct CodeGen {
15701582 LLVMValueRef return_address_fn_val;
15711583 LLVMValueRef frame_address_fn_val;
15721584 bool error_during_imports;
1573 TypeTableEntry *err_tag_type;
15741585
15751586 const char **clang_argv;
15761587 size_t clang_argv_len;
......@@ -1584,7 +1595,9 @@ struct CodeGen {
15841595
15851596 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;
15881601 bool generate_error_name_table;
15891602 LLVMValueRef err_name_table;
15901603 size_t largest_err_name_len;
......@@ -1617,6 +1630,10 @@ struct CodeGen {
16171630 TypeTableEntry *align_amt_type;
16181631 TypeTableEntry *stack_trace_type;
16191632 TypeTableEntry *ptr_to_stack_trace_type;
1633
1634 ZigList<ZigLLVMDIType **> error_di_types;
1635
1636 ZigList<Buf *> forbidden_libs;
16201637};
16211638
16221639enum VarLinkage {
......@@ -1653,6 +1670,7 @@ struct ErrorTableEntry {
16531670 Buf name;
16541671 uint32_t value;
16551672 AstNode *decl_node;
1673 TypeTableEntry *set_with_only_this_in_it;
16561674 // If we generate a constant error name value for this error, we memoize it here.
16571675 // The type of this is array
16581676 ConstExprValue *cached_error_name_val;
......@@ -1920,6 +1938,7 @@ enum IrInstructionId {
19201938 IrInstructionIdArgType,
19211939 IrInstructionIdExport,
19221940 IrInstructionIdErrorReturnTrace,
1941 IrInstructionIdErrorUnion,
19231942};
19241943
19251944struct IrInstruction {
......@@ -1996,7 +2015,6 @@ enum IrUnOp {
19962015 IrUnOpNegation,
19972016 IrUnOpNegationWrap,
19982017 IrUnOpDereference,
1999 IrUnOpError,
20002018 IrUnOpMaybe,
20012019};
20022020
......@@ -2039,6 +2057,7 @@ enum IrBinOp {
20392057 IrBinOpRemMod,
20402058 IrBinOpArrayCat,
20412059 IrBinOpArrayMult,
2060 IrBinOpMergeErrorSets,
20422061};
20432062
20442063struct IrInstructionBinOp {
......@@ -2750,6 +2769,13 @@ struct IrInstructionErrorReturnTrace {
27502769 IrInstruction base;
27512770};
27522771
2772struct IrInstructionErrorUnion {
2773 IrInstruction base;
2774
2775 IrInstruction *err_set;
2776 IrInstruction *payload;
2777};
2778
27532779static const size_t slice_ptr_index = 0;
27542780static const size_t slice_len_index = 1;
27552781
src/analyze.cpp+169-201
......@@ -224,7 +224,7 @@ bool type_is_complete(TypeTableEntry *type_entry) {
224224 case TypeTableEntryIdNullLit:
225225 case TypeTableEntryIdMaybe:
226226 case TypeTableEntryIdErrorUnion:
227 case TypeTableEntryIdPureError:
227 case TypeTableEntryIdErrorSet:
228228 case TypeTableEntryIdFn:
229229 case TypeTableEntryIdNamespace:
230230 case TypeTableEntryIdBlock:
......@@ -260,7 +260,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) {
260260 case TypeTableEntryIdNullLit:
261261 case TypeTableEntryIdMaybe:
262262 case TypeTableEntryIdErrorUnion:
263 case TypeTableEntryIdPureError:
263 case TypeTableEntryIdErrorSet:
264264 case TypeTableEntryIdFn:
265265 case TypeTableEntryIdNamespace:
266266 case TypeTableEntryIdBlock:
......@@ -514,29 +514,47 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
514514 }
515515}
516516
517TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
518 if (child_type->error_parent)
519 return child_type->error_parent;
517TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, TypeTableEntry *payload_type) {
518 assert(err_set_type->id == TypeTableEntryIdErrorSet);
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
521531 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion);
522532 entry->is_copyable = true;
523 assert(child_type->type_ref);
524 assert(child_type->di_type);
525 ensure_complete_type(g, child_type);
533 assert(payload_type->di_type);
534 ensure_complete_type(g, payload_type);
526535
527536 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;
531
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;
539 entry->data.error_union.err_set_type = err_set_type;
540 entry->data.error_union.payload_type = payload_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;
536554 } else {
537555 LLVMTypeRef elem_types[] = {
538 g->err_tag_type->type_ref,
539 child_type->type_ref,
556 err_set_type->type_ref,
557 payload_type->type_ref,
540558 };
541559 entry->type_ref = LLVMStructType(elem_types, 2, false);
542560
......@@ -547,12 +565,12 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
547565 ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name),
548566 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);
551 uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(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);
569 uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, err_set_type->type_ref);
552570 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);
555 uint64_t value_debug_align_in_bits = 8*LLVMABISizeOfType(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);
573 uint64_t value_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, payload_type->type_ref);
556574 uint64_t value_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref,
557575 err_union_payload_index);
558576
......@@ -565,13 +583,13 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
565583 tag_debug_size_in_bits,
566584 tag_debug_align_in_bits,
567585 tag_offset_in_bits,
568 0, child_type->di_type),
586 0, err_set_type->di_type),
569587 ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),
570588 "value", di_file, line,
571589 value_debug_size_in_bits,
572590 value_debug_align_in_bits,
573591 value_offset_in_bits,
574 0, child_type->di_type),
592 0, payload_type->di_type),
575593 };
576594
577595 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
......@@ -587,7 +605,7 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
587605 entry->di_type = replacement_di_type;
588606 }
589607
590 child_type->error_parent = entry;
608 g->type_table.put(type_id, entry);
591609 return entry;
592610}
593611
......@@ -937,7 +955,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
937955 handle_is_ptr(fn_type_id->return_type);
938956 bool prefix_arg_error_return_trace = g->have_err_ret_tracing &&
939957 (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion ||
940 fn_type_id->return_type->id == TypeTableEntryIdPureError);
958 fn_type_id->return_type->id == TypeTableEntryIdErrorSet);
941959 // +1 for maybe making the first argument the return value
942960 // +1 for maybe last argument the error return trace
943961 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) {
11771195 case TypeTableEntryIdUndefLit:
11781196 case TypeTableEntryIdNullLit:
11791197 case TypeTableEntryIdErrorUnion:
1180 case TypeTableEntryIdPureError:
1198 case TypeTableEntryIdErrorSet:
11811199 case TypeTableEntryIdNamespace:
11821200 case TypeTableEntryIdBlock:
11831201 case TypeTableEntryIdBoundFn:
......@@ -1218,7 +1236,7 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
12181236 case TypeTableEntryIdUndefLit:
12191237 case TypeTableEntryIdNullLit:
12201238 case TypeTableEntryIdErrorUnion:
1221 case TypeTableEntryIdPureError:
1239 case TypeTableEntryIdErrorSet:
12221240 case TypeTableEntryIdNamespace:
12231241 case TypeTableEntryIdBlock:
12241242 case TypeTableEntryIdBoundFn:
......@@ -1263,7 +1281,23 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
12631281 zig_unreachable();
12641282}
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) {
12671301 assert(proto_node->type == NodeTypeFnProto);
12681302 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
13591393 case TypeTableEntryIdStruct:
13601394 case TypeTableEntryIdMaybe:
13611395 case TypeTableEntryIdErrorUnion:
1362 case TypeTableEntryIdPureError:
1396 case TypeTableEntryIdErrorSet:
13631397 case TypeTableEntryIdEnum:
13641398 case TypeTableEntryIdUnion:
13651399 case TypeTableEntryIdFn:
......@@ -1382,13 +1416,19 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
13821416 }
13831417 }
13841418
1385 fn_type_id.return_type = (fn_proto->return_type == nullptr) ?
1386 g->builtin_types.entry_void : analyze_type_expr(g, child_scope, fn_proto->return_type);
1387
1388 if (type_is_invalid(fn_type_id.return_type)) {
1419 TypeTableEntry *specified_return_type = analyze_type_expr(g, child_scope, fn_proto->return_type);
1420 if (type_is_invalid(specified_return_type)) {
1421 fn_type_id.return_type = g->builtin_types.entry_invalid;
13891422 return g->builtin_types.entry_invalid;
13901423 }
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
13921432 if (fn_type_id.cc != CallingConventionUnspecified && !type_allowed_in_extern(g, fn_type_id.return_type)) {
13931433 add_node_error(g, fn_proto->return_type,
13941434 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
14341474 case TypeTableEntryIdStruct:
14351475 case TypeTableEntryIdMaybe:
14361476 case TypeTableEntryIdErrorUnion:
1437 case TypeTableEntryIdPureError:
1477 case TypeTableEntryIdErrorSet:
14381478 case TypeTableEntryIdEnum:
14391479 case TypeTableEntryIdUnion:
14401480 case TypeTableEntryIdFn:
......@@ -2756,7 +2796,8 @@ TypeTableEntry *get_test_fn_type(CodeGen *g) {
27562796 return g->test_fn_type;
27572797
27582798 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);
27602801 g->test_fn_type = get_fn_type(g, &fn_type_id);
27612802 return g->test_fn_type;
27622803}
......@@ -2824,7 +2865,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
28242865
28252866 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
28292870 if (fn_proto->section_expr != nullptr) {
28302871 if (fn_table_entry->body_node == nullptr) {
......@@ -2949,29 +2990,6 @@ static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope
29492990 g->resolve_queue.append(&tld_fn->base);
29502991}
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
29752993static void preview_comptime_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) {
29762994 assert(node->type == NodeTypeCompTime);
29772995
......@@ -3045,10 +3063,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
30453063 import->use_decls.append(node);
30463064 break;
30473065 }
3048 case NodeTypeErrorValueDecl:
3049 // error value declarations do not depend on other top level decls
3050 preview_error_value_decl(g, node);
3051 break;
30523066 case NodeTypeTestDecl:
30533067 preview_test_decl(g, node, decls_scope);
30543068 break;
......@@ -3097,6 +3111,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
30973111 case NodeTypeVarLiteral:
30983112 case NodeTypeIfErrorExpr:
30993113 case NodeTypeTestExpr:
3114 case NodeTypeErrorSetDecl:
31003115 zig_unreachable();
31013116 }
31023117}
......@@ -3147,7 +3162,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
31473162 case TypeTableEntryIdStruct:
31483163 case TypeTableEntryIdMaybe:
31493164 case TypeTableEntryIdErrorUnion:
3150 case TypeTableEntryIdPureError:
3165 case TypeTableEntryIdErrorSet:
31513166 case TypeTableEntryIdEnum:
31523167 case TypeTableEntryIdUnion:
31533168 case TypeTableEntryIdFn:
......@@ -3362,108 +3377,6 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *so
33623377 g->tld_ref_source_node_stack.pop();
33633378}
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
34673380Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) {
34683381 // we must resolve all the use decls
34693382 ImportTableEntry *import = get_scope_import(scope);
......@@ -3625,7 +3538,7 @@ static bool is_container(TypeTableEntry *type_entry) {
36253538 case TypeTableEntryIdNullLit:
36263539 case TypeTableEntryIdMaybe:
36273540 case TypeTableEntryIdErrorUnion:
3628 case TypeTableEntryIdPureError:
3541 case TypeTableEntryIdErrorSet:
36293542 case TypeTableEntryIdFn:
36303543 case TypeTableEntryIdNamespace:
36313544 case TypeTableEntryIdBlock:
......@@ -3673,7 +3586,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
36733586 case TypeTableEntryIdNullLit:
36743587 case TypeTableEntryIdMaybe:
36753588 case TypeTableEntryIdErrorUnion:
3676 case TypeTableEntryIdPureError:
3589 case TypeTableEntryIdErrorSet:
36773590 case TypeTableEntryIdFn:
36783591 case TypeTableEntryIdNamespace:
36793592 case TypeTableEntryIdBlock:
......@@ -3765,6 +3678,27 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari
37653678 }
37663679}
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
37683702void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_type_node) {
37693703 TypeTableEntry *fn_type = fn_table_entry->type_entry;
37703704 assert(!fn_type->data.fn.is_generic);
......@@ -3774,14 +3708,49 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
37743708 &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node);
37753709 fn_table_entry->implicit_return_type = block_return_type;
37763710
3777 if (block_return_type->id == TypeTableEntryIdInvalid ||
3778 fn_table_entry->analyzed_executable.invalid)
3779 {
3711 if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) {
37803712 assert(g->errors.length > 0);
37813713 fn_table_entry->anal_state = FnAnalStateInvalid;
37823714 return;
37833715 }
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
37853754 if (g->verbose_ir) {
37863755 fprintf(stderr, "{ // (analyzed)\n");
37873756 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
37913760 fn_table_entry->anal_state = FnAnalStateComplete;
37923761}
37933762
3794static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
3763void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
37953764 assert(fn_table_entry->anal_state != FnAnalStateProbing);
37963765 if (fn_table_entry->anal_state != FnAnalStateReady)
37973766 return;
......@@ -4022,7 +3991,8 @@ void semantic_analyze(CodeGen *g) {
40223991 for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) {
40233992 Tld *tld = g->resolve_queue.at(g->resolve_queue_index);
40243993 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);
40263996 }
40273997
40283998 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) {
41144084 case TypeTableEntryIdInt:
41154085 case TypeTableEntryIdFloat:
41164086 case TypeTableEntryIdPointer:
4117 case TypeTableEntryIdPureError:
4087 case TypeTableEntryIdErrorSet:
41184088 case TypeTableEntryIdFn:
41194089 case TypeTableEntryIdEnum:
41204090 return false;
......@@ -4122,7 +4092,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
41224092 case TypeTableEntryIdStruct:
41234093 return type_has_bits(type_entry);
41244094 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);
41264096 case TypeTableEntryIdMaybe:
41274097 return type_has_bits(type_entry->data.maybe.child_type) &&
41284098 type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer &&
......@@ -4386,9 +4356,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
43864356 case TypeTableEntryIdErrorUnion:
43874357 // TODO better hashing algorithm
43884358 return 3415065496;
4389 case TypeTableEntryIdPureError:
4390 // TODO better hashing algorithm
4391 return 2630160122;
4359 case TypeTableEntryIdErrorSet:
4360 assert(const_val->data.x_err_set != nullptr);
4361 return const_val->data.x_err_set->value ^ 2630160122;
43924362 case TypeTableEntryIdFn:
43934363 return 4133894920 ^ hash_ptr(const_val->data.x_fn.fn_entry);
43944364 case TypeTableEntryIdNamespace:
......@@ -4515,7 +4485,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
45154485 case TypeTableEntryIdMaybe:
45164486 case TypeTableEntryIdErrorUnion:
45174487 case TypeTableEntryIdEnum:
4518 case TypeTableEntryIdPureError:
4488 case TypeTableEntryIdErrorSet:
45194489 case TypeTableEntryIdFn:
45204490 case TypeTableEntryIdBool:
45214491 case TypeTableEntryIdInt:
......@@ -4894,8 +4864,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
48944864 return a->data.x_type == b->data.x_type;
48954865 case TypeTableEntryIdVoid:
48964866 return true;
4897 case TypeTableEntryIdPureError:
4898 return a->data.x_pure_err == b->data.x_pure_err;
4867 case TypeTableEntryIdErrorSet:
4868 return a->data.x_err_set->value == b->data.x_err_set->value;
48994869 case TypeTableEntryIdFn:
49004870 return a->data.x_fn.fn_entry == b->data.x_fn.fn_entry;
49014871 case TypeTableEntryIdBool:
......@@ -5256,9 +5226,9 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
52565226 buf_appendf(buf, "(union %s constant)", buf_ptr(&type_entry->name));
52575227 return;
52585228 }
5259 case TypeTableEntryIdPureError:
5229 case TypeTableEntryIdErrorSet:
52605230 {
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));
52625232 return;
52635233 }
52645234 case TypeTableEntryIdArgTuple:
......@@ -5319,8 +5289,7 @@ uint32_t type_id_hash(TypeId x) {
53195289 case TypeTableEntryIdUndefLit:
53205290 case TypeTableEntryIdNullLit:
53215291 case TypeTableEntryIdMaybe:
5322 case TypeTableEntryIdErrorUnion:
5323 case TypeTableEntryIdPureError:
5292 case TypeTableEntryIdErrorSet:
53245293 case TypeTableEntryIdEnum:
53255294 case TypeTableEntryIdUnion:
53265295 case TypeTableEntryIdFn:
......@@ -5329,6 +5298,8 @@ uint32_t type_id_hash(TypeId x) {
53295298 case TypeTableEntryIdBoundFn:
53305299 case TypeTableEntryIdArgTuple:
53315300 zig_unreachable();
5301 case TypeTableEntryIdErrorUnion:
5302 return hash_ptr(x.data.error_union.err_set_type) ^ hash_ptr(x.data.error_union.payload_type);
53325303 case TypeTableEntryIdPointer:
53335304 return hash_ptr(x.data.pointer.child_type) +
53345305 (x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) +
......@@ -5363,8 +5334,7 @@ bool type_id_eql(TypeId a, TypeId b) {
53635334 case TypeTableEntryIdUndefLit:
53645335 case TypeTableEntryIdNullLit:
53655336 case TypeTableEntryIdMaybe:
5366 case TypeTableEntryIdErrorUnion:
5367 case TypeTableEntryIdPureError:
5337 case TypeTableEntryIdErrorSet:
53685338 case TypeTableEntryIdEnum:
53695339 case TypeTableEntryIdUnion:
53705340 case TypeTableEntryIdFn:
......@@ -5374,6 +5344,10 @@ bool type_id_eql(TypeId a, TypeId b) {
53745344 case TypeTableEntryIdArgTuple:
53755345 case TypeTableEntryIdOpaque:
53765346 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
53775351 case TypeTableEntryIdPointer:
53785352 return a.data.pointer.child_type == b.data.pointer.child_type &&
53795353 a.data.pointer.is_const == b.data.pointer.is_const &&
......@@ -5478,7 +5452,7 @@ static const TypeTableEntryId all_type_ids[] = {
54785452 TypeTableEntryIdNullLit,
54795453 TypeTableEntryIdMaybe,
54805454 TypeTableEntryIdErrorUnion,
5481 TypeTableEntryIdPureError,
5455 TypeTableEntryIdErrorSet,
54825456 TypeTableEntryIdEnum,
54835457 TypeTableEntryIdUnion,
54845458 TypeTableEntryIdFn,
......@@ -5533,7 +5507,7 @@ size_t type_id_index(TypeTableEntryId id) {
55335507 return 13;
55345508 case TypeTableEntryIdErrorUnion:
55355509 return 14;
5536 case TypeTableEntryIdPureError:
5510 case TypeTableEntryIdErrorSet:
55375511 return 15;
55385512 case TypeTableEntryIdEnum:
55395513 return 16;
......@@ -5590,8 +5564,8 @@ const char *type_id_name(TypeTableEntryId id) {
55905564 return "Nullable";
55915565 case TypeTableEntryIdErrorUnion:
55925566 return "ErrorUnion";
5593 case TypeTableEntryIdPureError:
5594 return "Error";
5567 case TypeTableEntryIdErrorSet:
5568 return "ErrorSet";
55955569 case TypeTableEntryIdEnum:
55965570 return "Enum";
55975571 case TypeTableEntryIdUnion:
......@@ -5640,17 +5614,6 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) {
56405614 return link_lib;
56415615}
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
56545617uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) {
56555618 type_ensure_zero_bits_known(g, type_entry);
56565619 if (type_entry->zero_bits) return 0;
......@@ -5696,3 +5659,8 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
56965659 return var_value;
56975660}
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);
3030TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,
3131 AstNode *decl_node, const char *name, ContainerLayout layout);
3232TypeTableEntry *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);
3434TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry);
3535TypeTableEntry *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *name);
3636TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
......@@ -46,8 +46,6 @@ bool type_has_bits(TypeTableEntry *type_entry);
4646ImportTableEntry *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);
5149VariableTableEntry *find_variable(CodeGen *g, Scope *orig_context, Buf *name);
5250Tld *find_decl(CodeGen *g, Scope *scope, Buf *name);
5351void 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
5856TypeTableEntry *container_ref_type(TypeTableEntry *type_entry);
5957bool type_is_complete(TypeTableEntry *type_entry);
6058bool type_is_invalid(TypeTableEntry *type_entry);
59bool type_is_global_error_set(TypeTableEntry *err_set_type);
6160bool type_has_zero_bits_known(TypeTableEntry *type_entry);
6261void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry);
6362ScopeDecls *get_container_scope(TypeTableEntry *type_entry);
......@@ -176,7 +175,6 @@ bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry);
176175LinkLib *create_link_lib(Buf *name);
177176bool calling_convention_does_first_arg_return(CallingConvention cc);
178177LinkLib *add_link_lib(CodeGen *codegen, Buf *lib);
179void add_link_lib_symbol(CodeGen *g, Buf *lib_name, Buf *symbol_name);
180178
181179uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry);
182180TypeTableEntry *get_align_amt_type(CodeGen *g);
......@@ -188,6 +186,8 @@ void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, G
188186
189187ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
190188TypeTableEntry *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
193193#endif
src/ast_render.cpp+26-7
......@@ -49,11 +49,12 @@ static const char *bin_op_str(BinOpType bin_op) {
4949 case BinOpTypeAssignBitAnd: return "&=";
5050 case BinOpTypeAssignBitXor: return "^=";
5151 case BinOpTypeAssignBitOr: return "|=";
52 case BinOpTypeAssignBoolAnd: return "&&=";
53 case BinOpTypeAssignBoolOr: return "||=";
52 case BinOpTypeAssignMergeErrorSets: return "||=";
5453 case BinOpTypeUnwrapMaybe: return "??";
5554 case BinOpTypeArrayCat: return "++";
5655 case BinOpTypeArrayMult: return "**";
56 case BinOpTypeErrorUnion: return "!";
57 case BinOpTypeMergeErrorSets: return "||";
5758 }
5859 zig_unreachable();
5960}
......@@ -67,7 +68,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
6768 case PrefixOpBinNot: return "~";
6869 case PrefixOpDereference: return "*";
6970 case PrefixOpMaybe: return "?";
70 case PrefixOpError: return "%";
7171 case PrefixOpUnwrapMaybe: return "??";
7272 }
7373 zig_unreachable();
......@@ -174,8 +174,6 @@ static const char *node_type_str(NodeType node_type) {
174174 return "Defer";
175175 case NodeTypeVariableDeclaration:
176176 return "VariableDeclaration";
177 case NodeTypeErrorValueDecl:
178 return "ErrorValueDecl";
179177 case NodeTypeTestDecl:
180178 return "TestDecl";
181179 case NodeTypeIntLiteral:
......@@ -244,6 +242,8 @@ static const char *node_type_str(NodeType node_type) {
244242 return "IfErrorExpr";
245243 case NodeTypeTestExpr:
246244 return "TestExpr";
245 case NodeTypeErrorSetDecl:
246 return "ErrorSetDecl";
247247 }
248248 zig_unreachable();
249249}
......@@ -396,7 +396,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
396396
397397 if (child->type == NodeTypeUse ||
398398 child->type == NodeTypeVariableDeclaration ||
399 child->type == NodeTypeErrorValueDecl ||
400399 child->type == NodeTypeFnProto)
401400 {
402401 fprintf(ar->f, ";");
......@@ -452,6 +451,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
452451 AstNode *return_type_node = node->data.fn_proto.return_type;
453452 assert(return_type_node != nullptr);
454453 fprintf(ar->f, " ");
454 if (node->data.fn_proto.auto_err_set) {
455 fprintf(ar->f, "!");
456 }
455457 render_node_grouped(ar, return_type_node);
456458 break;
457459 }
......@@ -1017,9 +1019,26 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
10171019 render_node_ungrouped(ar, node->data.unwrap_err_expr.op2);
10181020 break;
10191021 }
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 }
10201040 case NodeTypeFnDecl:
10211041 case NodeTypeParamDecl:
1022 case NodeTypeErrorValueDecl:
10231042 case NodeTypeTestDecl:
10241043 case NodeTypeStructField:
10251044 case NodeTypeUse:
src/codegen.cpp+156-76
......@@ -92,9 +92,6 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
9292 g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib);
9393 buf_resize(&g->global_asm, 0);
9494
95 // reserve index 0 to indicate no error
96 g->error_decls.append(nullptr);
97
9895 if (root_src_path) {
9996 Buf *src_basename = buf_alloc();
10097 Buf *src_dir = buf_alloc();
......@@ -256,6 +253,10 @@ LinkLib *codegen_add_link_lib(CodeGen *g, Buf *name) {
256253 return add_link_lib(g, name);
257254}
258255
256void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib) {
257 codegen->forbidden_libs.append(lib);
258}
259
259260void codegen_add_framework(CodeGen *g, const char *framework) {
260261 g->darwin_frameworks.append(buf_create_from_str(framework));
261262}
......@@ -410,7 +411,7 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e
410411 }
411412 TypeTableEntry *fn_type = fn_table_entry->type_entry;
412413 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) {
414415 return UINT32_MAX;
415416 }
416417 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
14421443 is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError;
14431444 // TODO: emit a branch to check if the return value is an error
14441445 }
1445 } else if (return_type->id == TypeTableEntryIdPureError) {
1446 } else if (return_type->id == TypeTableEntryIdErrorSet) {
14461447 is_err_return = true;
14471448 }
14481449 if (is_err_return) {
......@@ -1789,7 +1790,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
17891790
17901791 assert(op1->value.type == op2->value.type || op_id == IrBinOpBitShiftLeftLossy ||
17911792 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));
17931795 TypeTableEntry *type_entry = op1->value.type;
17941796
17951797 bool want_runtime_safety = bin_op_instruction->safety_check_on &&
......@@ -1802,6 +1804,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
18021804 case IrBinOpArrayCat:
18031805 case IrBinOpArrayMult:
18041806 case IrBinOpRemUnspecified:
1807 case IrBinOpMergeErrorSets:
18051808 zig_unreachable();
18061809 case IrBinOpBoolOr:
18071810 return LLVMBuildOr(g->builder, op1_value, op2_value, "");
......@@ -1823,7 +1826,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
18231826 } else if (type_entry->id == TypeTableEntryIdEnum) {
18241827 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
18251828 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
1826 } else if (type_entry->id == TypeTableEntryIdPureError ||
1829 } else if (type_entry->id == TypeTableEntryIdErrorSet ||
18271830 type_entry->id == TypeTableEntryIdPointer ||
18281831 type_entry->id == TypeTableEntryIdBool)
18291832 {
......@@ -1955,6 +1958,54 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
19551958 zig_unreachable();
19561959}
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
19582009static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
19592010 IrInstructionCast *cast_instruction)
19602011{
......@@ -2078,6 +2129,11 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
20782129 assert(wanted_type->id == TypeTableEntryIdInt);
20792130 assert(actual_type->id == TypeTableEntryIdBool);
20802131 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;
20812137 }
20822138 zig_unreachable();
20832139}
......@@ -2139,7 +2195,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,
21392195
21402196static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) {
21412197 TypeTableEntry *wanted_type = instruction->base.value.type;
2142 assert(wanted_type->id == TypeTableEntryIdPureError);
2198 assert(wanted_type->id == TypeTableEntryIdErrorSet);
21432199
21442200 TypeTableEntry *actual_type = instruction->target->value.type;
21452201 assert(actual_type->id == TypeTableEntryIdInt);
......@@ -2148,32 +2204,7 @@ static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, I
21482204 LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
21492205
21502206 if (ir_want_runtime_safety(g, &instruction->base)) {
2151 LLVMValueRef zero = LLVMConstNull(actual_type->type_ref);
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);
2207 add_error_range_check(g, wanted_type, actual_type, target_val);
21772208 }
21782209
21792210 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
21872218 TypeTableEntry *actual_type = instruction->target->value.type;
21882219 LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
21892220
2190 if (actual_type->id == TypeTableEntryIdPureError) {
2221 if (actual_type->id == TypeTableEntryIdErrorSet) {
21912222 return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
21922223 g->err_tag_type, wanted_type, target_val);
21932224 } 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)) {
21952229 return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
21962230 g->err_tag_type, wanted_type, target_val);
21972231 } else {
2198 zig_panic("TODO");
2232 zig_panic("TODO err to int when error union payload type not void");
21992233 }
22002234 } else {
22012235 zig_unreachable();
......@@ -2235,7 +2269,6 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
22352269
22362270 switch (op_id) {
22372271 case IrUnOpInvalid:
2238 case IrUnOpError:
22392272 case IrUnOpMaybe:
22402273 case IrUnOpDereference:
22412274 zig_unreachable();
......@@ -2489,7 +2522,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
24892522 TypeTableEntry *src_return_type = fn_type_id->return_type;
24902523 bool ret_has_bits = type_has_bits(src_return_type);
24912524 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);
24932526 size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0);
24942527 bool is_var_args = fn_type_id->is_var_args;
24952528 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
......@@ -2907,7 +2940,7 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstru
29072940static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrInstructionErrName *instruction) {
29082941 assert(g->generate_error_name_table);
29092942
2910 if (g->error_decls.length == 1) {
2943 if (g->errors_by_index.length == 1) {
29112944 LLVMBuildUnreachable(g->builder);
29122945 return nullptr;
29132946 }
......@@ -2915,7 +2948,7 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI
29152948 LLVMValueRef err_val = ir_llvm_value(g, instruction->value);
29162949 if (ir_want_runtime_safety(g, &instruction->base)) {
29172950 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);
29192952 add_bounds_check(g, err_val, LLVMIntNE, zero, LLVMIntULT, end_val);
29202953 }
29212954
......@@ -3393,11 +3426,11 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable,
33933426
33943427static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) {
33953428 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;
33973430 LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->value);
33983431
33993432 LLVMValueRef err_val;
3400 if (type_has_bits(child_type)) {
3433 if (type_has_bits(payload_type)) {
34013434 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
34023435 err_val = gen_load_untyped(g, err_val_ptr, 0, false, "");
34033436 } else {
......@@ -3412,11 +3445,11 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab
34123445 TypeTableEntry *ptr_type = instruction->value->value.type;
34133446 assert(ptr_type->id == TypeTableEntryIdPointer);
34143447 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;
34163449 LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
34173450 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)) {
34203453 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
34213454 return gen_load_untyped(g, err_val_ptr, 0, false, "");
34223455 } else {
......@@ -3428,13 +3461,17 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
34283461 TypeTableEntry *ptr_type = instruction->value->value.type;
34293462 assert(ptr_type->id == TypeTableEntryIdPointer);
34303463 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;
34323465 LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
34333466 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) {
34363473 LLVMValueRef err_val;
3437 if (type_has_bits(child_type)) {
3474 if (type_has_bits(payload_type)) {
34383475 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
34393476 err_val = gen_load_untyped(g, err_val_ptr, 0, false, "");
34403477 } else {
......@@ -3452,7 +3489,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
34523489 LLVMPositionBuilderAtEnd(g->builder, ok_block);
34533490 }
34543491
3455 if (type_has_bits(child_type)) {
3492 if (type_has_bits(payload_type)) {
34563493 return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, "");
34573494 } else {
34583495 return nullptr;
......@@ -3493,10 +3530,12 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable
34933530
34943531 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
34973536 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))
35003539 return err_val;
35013540
35023541 assert(instruction->tmp_ptr);
......@@ -3512,11 +3551,16 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
35123551
35133552 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
35173561 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))
35203564 return ok_err_val;
35213565
35223566 assert(instruction->tmp_ptr);
......@@ -3527,7 +3571,7 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
35273571 gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false);
35283572
35293573 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
35323576 return instruction->tmp_ptr;
35333577}
......@@ -3700,6 +3744,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
37003744 case IrInstructionIdArgType:
37013745 case IrInstructionIdTagType:
37023746 case IrInstructionIdExport:
3747 case IrInstructionIdErrorUnion:
37033748 zig_unreachable();
37043749 case IrInstructionIdReturn:
37053750 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
39333978 case TypeTableEntryIdUndefLit:
39343979 case TypeTableEntryIdNullLit:
39353980 case TypeTableEntryIdErrorUnion:
3936 case TypeTableEntryIdPureError:
3981 case TypeTableEntryIdErrorSet:
39373982 case TypeTableEntryIdNamespace:
39383983 case TypeTableEntryIdBlock:
39393984 case TypeTableEntryIdBoundFn:
......@@ -4026,10 +4071,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
40264071 switch (type_entry->id) {
40274072 case TypeTableEntryIdInt:
40284073 return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint);
4029 case TypeTableEntryIdPureError:
4030 assert(const_val->data.x_pure_err);
4031 return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref,
4032 const_val->data.x_pure_err->value, false);
4074 case TypeTableEntryIdErrorSet:
4075 assert(const_val->data.x_err_set != nullptr);
4076 return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref,
4077 const_val->data.x_err_set->value, false);
40334078 case TypeTableEntryIdFloat:
40344079 switch (type_entry->data.floating.bit_count) {
40354080 case 32:
......@@ -4330,17 +4375,22 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
43304375 }
43314376 case TypeTableEntryIdErrorUnion:
43324377 {
4333 TypeTableEntry *child_type = type_entry->data.error.child_type;
4334 if (!type_has_bits(child_type)) {
4378 TypeTableEntry *payload_type = type_entry->data.error_union.payload_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));
43354382 uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0;
43364383 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);
43374387 } else {
43384388 LLVMValueRef err_tag_value;
43394389 LLVMValueRef err_payload_value;
43404390 bool make_unnamed_struct;
43414391 if (const_val->data.x_err_union.err) {
43424392 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);
43444394 make_unnamed_struct = false;
43454395 } else {
43464396 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
44104460}
44114461
44124462static 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) {
44144464 return;
44154465 }
44164466
4417 assert(g->error_decls.length > 0);
4467 assert(g->errors_by_index.length > 0);
44184468
44194469 TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
44204470 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);
44234473 values[0] = LLVMGetUndef(str_type->type_ref);
4424 for (size_t i = 1; i < g->error_decls.length; i += 1) {
4425 AstNode *error_decl_node = g->error_decls.at(i);
4426 assert(error_decl_node->type == NodeTypeErrorValueDecl);
4427 Buf *name = error_decl_node->data.error_value_decl.name;
4474 for (size_t i = 1; i < g->errors_by_index.length; i += 1) {
4475 ErrorTableEntry *err_entry = g->errors_by_index.at(i);
4476 Buf *name = &err_entry->name;
44284477
44294478 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) {
44434492 values[i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2);
44444493 }
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
44484497 g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init),
44494498 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) {
45754624
45764625 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
45784649 generate_error_name_table(g);
45794650 generate_enum_name_tables(g);
45804651
......@@ -5176,16 +5247,24 @@ static void define_builtin_types(CodeGen *g) {
51765247 }
51775248
51785249 {
5179 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError);
5250 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorSet);
51805251 buf_init_from_str(&entry->name, "error");
5252 entry->data.error_set.err_count = UINT32_MAX;
51815253
51825254 // TODO allow overriding this type and keep track of max value and emit an
51835255 // error if there are too many errors declared
51845256 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;
51875259 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
51905269 g->primitive_type_table.put(&entry->name, entry);
51915270 }
......@@ -5815,7 +5894,7 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry
58155894 case TypeTableEntryIdBoundFn:
58165895 case TypeTableEntryIdArgTuple:
58175896 case TypeTableEntryIdErrorUnion:
5818 case TypeTableEntryIdPureError:
5897 case TypeTableEntryIdErrorSet:
58195898 zig_unreachable();
58205899 case TypeTableEntryIdVoid:
58215900 case TypeTableEntryIdUnreachable:
......@@ -5988,7 +6067,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
59886067 return;
59896068 }
59906069 case TypeTableEntryIdErrorUnion:
5991 case TypeTableEntryIdPureError:
6070 case TypeTableEntryIdErrorSet:
59926071 case TypeTableEntryIdFn:
59936072 zig_panic("TODO implement get_c_type for more types");
59946073 case TypeTableEntryIdInvalid:
......@@ -6155,7 +6234,7 @@ static void gen_h_file(CodeGen *g) {
61556234 case TypeTableEntryIdUndefLit:
61566235 case TypeTableEntryIdNullLit:
61576236 case TypeTableEntryIdErrorUnion:
6158 case TypeTableEntryIdPureError:
6237 case TypeTableEntryIdErrorSet:
61596238 case TypeTableEntryIdNamespace:
61606239 case TypeTableEntryIdBlock:
61616240 case TypeTableEntryIdBoundFn:
......@@ -6265,3 +6344,4 @@ PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir,
62656344 }
62666345 return pkg;
62676346}
6347
src/codegen.hpp+1
......@@ -36,6 +36,7 @@ void codegen_set_kernel32_lib_dir(CodeGen *codegen, Buf *kernel32_lib_dir);
3636void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker);
3737void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole);
3838void codegen_add_lib_dir(CodeGen *codegen, const char *dir);
39void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib);
3940LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib);
4041void codegen_add_framework(CodeGen *codegen, const char *name);
4142void 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) {
4545 return { true, is_const, is_volatile };
4646}
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
48101static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
49102static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval);
50103static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);
......@@ -580,6 +633,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorReturnTrace
580633 return IrInstructionIdErrorReturnTrace;
581634}
582635
636static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnion *) {
637 return IrInstructionIdErrorUnion;
638}
639
583640template<typename T>
584641static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
585642 T *special_instruction = allocate<T>(1);
......@@ -2326,6 +2383,19 @@ static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope,
23262383 return &instruction->base;
23272384}
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
23292399static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
23302400 results[ReturnKindUnconditional] = 0;
23312401 results[ReturnKindError] = 0;
......@@ -2800,6 +2870,23 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As
28002870 return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values);
28012871}
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
28032890static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) {
28042891 assert(node->type == NodeTypeBinOpExpr);
28052892
......@@ -2835,10 +2922,8 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
28352922 return ir_gen_assign_op(irb, scope, node, IrBinOpBinXor);
28362923 case BinOpTypeAssignBitOr:
28372924 return ir_gen_assign_op(irb, scope, node, IrBinOpBinOr);
2838 case BinOpTypeAssignBoolAnd:
2839 return ir_gen_assign_op(irb, scope, node, IrBinOpBoolAnd);
2840 case BinOpTypeAssignBoolOr:
2841 return ir_gen_assign_op(irb, scope, node, IrBinOpBoolOr);
2925 case BinOpTypeAssignMergeErrorSets:
2926 return ir_gen_assign_op(irb, scope, node, IrBinOpMergeErrorSets);
28422927 case BinOpTypeBoolOr:
28432928 return ir_gen_bool_or(irb, scope, node);
28442929 case BinOpTypeBoolAnd:
......@@ -2885,8 +2970,12 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
28852970 return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat);
28862971 case BinOpTypeArrayMult:
28872972 return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult);
2973 case BinOpTypeMergeErrorSets:
2974 return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets);
28882975 case BinOpTypeUnwrapMaybe:
28892976 return ir_gen_maybe_ok_or(irb, scope, node);
2977 case BinOpTypeErrorUnion:
2978 return ir_gen_error_union(irb, scope, node);
28902979 }
28912980 zig_unreachable();
28922981}
......@@ -3990,8 +4079,6 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
39904079 return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval);
39914080 case PrefixOpMaybe:
39924081 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);
39954082 case PrefixOpUnwrapMaybe:
39964083 return ir_gen_maybe_assert_ok(irb, scope, node, lval);
39974084 }
......@@ -4713,12 +4800,8 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
47134800 IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse");
47144801 IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "TryEnd");
47154802
4716 IrInstruction *is_comptime;
4717 if (ir_should_inline(irb->exec, scope)) {
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 }
4803 bool force_comptime = 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);
47224805 ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime);
47234806
47244807 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 *
47274810 if (var_symbol) {
47284811 IrInstruction *var_type = nullptr;
47294812 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);
47304814 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
47334817 IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, scope, node, err_val_ptr, false);
47344818 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
51655249
51665250static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) {
51675251 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);
51695253}
51705254
51715255static 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
52495333 Scope *err_scope;
52505334 if (var_node) {
52515335 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);
52545336 Buf *var_name = var_node->data.symbol_expr.symbol;
52555337 bool is_const = true;
52565338 bool is_shadowable = false;
......@@ -5258,7 +5340,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
52585340 is_const, is_const, is_shadowable, is_comptime);
52595341 err_scope = var->child_scope;
52605342 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);
52625344 } else {
52635345 err_scope = parent_scope;
52645346 }
......@@ -5348,6 +5430,135 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope,
53485430 return ir_build_const_type(irb, parent_scope, node, container_type);
53495431}
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
53515562static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
53525563 assert(node->type == NodeTypeFnProto);
53535564
......@@ -5401,7 +5612,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
54015612 case NodeTypeStructField:
54025613 case NodeTypeFnDef:
54035614 case NodeTypeFnDecl:
5404 case NodeTypeErrorValueDecl:
54055615 case NodeTypeTestDecl:
54065616 zig_unreachable();
54075617 case NodeTypeBlock:
......@@ -5482,6 +5692,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
54825692 return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval);
54835693 case NodeTypeFnProto:
54845694 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);
54855697 }
54865698 zig_unreachable();
54875699}
......@@ -6287,6 +6499,274 @@ static bool slice_is_const(TypeTableEntry *type) {
62876499 return type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
62886500}
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
62906770enum ImplicitCastMatchResult {
62916771 ImplicitCastMatchResultNo,
62926772 ImplicitCastMatchResultYes,
......@@ -6296,10 +6776,46 @@ enum ImplicitCastMatchResult {
62966776static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, TypeTableEntry *expected_type,
62976777 TypeTableEntry *actual_type, IrInstruction *value)
62986778{
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) {
63006782 return ImplicitCastMatchResultYes;
63016783 }
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
63036819 // implicit conversion from anything to var
63046820 if (expected_type->id == TypeTableEntryIdVar) {
63056821 return ImplicitCastMatchResultYes;
......@@ -6319,25 +6835,25 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
63196835 return ImplicitCastMatchResultYes;
63206836 }
63216837
6322 // implicit T to %T
6838 // implicit T to U!T
63236839 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))
63256841 {
63266842 return ImplicitCastMatchResultYes;
63276843 }
63286844
6329 // implicit conversion from pure error to error union type
6845 // implicit conversion from error set to error union type
63306846 if (expected_type->id == TypeTableEntryIdErrorUnion &&
6331 actual_type->id == TypeTableEntryIdPureError)
6847 actual_type->id == TypeTableEntryIdErrorSet)
63326848 {
63336849 return ImplicitCastMatchResultYes;
63346850 }
63356851
6336 // implicit conversion from T to %?T
6852 // implicit conversion from T to U!?T
63376853 if (expected_type->id == TypeTableEntryIdErrorUnion &&
6338 expected_type->data.error.child_type->id == TypeTableEntryIdMaybe &&
6854 expected_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe &&
63396855 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,
63416857 actual_type, value))
63426858 {
63436859 return ImplicitCastMatchResultYes;
......@@ -6374,7 +6890,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
63746890 assert(ptr_type->id == TypeTableEntryIdPointer);
63756891
63766892 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)
63786894 {
63796895 return ImplicitCastMatchResultYes;
63806896 }
......@@ -6392,7 +6908,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
63926908 TypeTableEntry *array_type = actual_type->data.pointer.child_type;
63936909
63946910 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)
63966912 {
63976913 return ImplicitCastMatchResultYes;
63986914 }
......@@ -6408,7 +6924,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
64086924 expected_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;
64096925 assert(ptr_type->id == TypeTableEntryIdPointer);
64106926 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)
64126928 {
64136929 return ImplicitCastMatchResultYes;
64146930 }
......@@ -6423,7 +6939,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
64236939 expected_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;
64246940 assert(ptr_type->id == TypeTableEntryIdPointer);
64256941 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)
64276943 {
64286944 return ImplicitCastMatchResultYes;
64296945 }
......@@ -6503,7 +7019,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
65037019 // implicitly take a const pointer to something
65047020 if (!type_requires_comptime(actual_type)) {
65057021 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) {
65077023 return ImplicitCastMatchResultYes;
65087024 }
65097025 }
......@@ -6511,13 +7027,39 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
65117027 return ImplicitCastMatchResultNo;
65127028}
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
65147036static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) {
65157037 assert(instruction_count >= 1);
65167038 IrInstruction *prev_inst = instructions[0];
65177039 if (type_is_invalid(prev_inst->value.type)) {
65187040 return ira->codegen->builtin_types.entry_invalid;
65197041 }
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
65217063 bool any_are_null = (prev_inst->value.type->id == TypeTableEntryIdNullLit);
65227064 bool convert_to_const_slice = false;
65237065 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
65387080 continue;
65397081 }
65407082
6541 if (prev_type->id == TypeTableEntryIdPureError) {
7083 if (prev_type->id == TypeTableEntryIdNullLit) {
65427084 prev_inst = cur_inst;
65437085 continue;
65447086 }
65457087
6546 if (prev_type->id == TypeTableEntryIdNullLit) {
6547 prev_inst = cur_inst;
7088 if (cur_type->id == TypeTableEntryIdNullLit) {
7089 any_are_null = true;
65487090 continue;
65497091 }
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) {
65527218 if (prev_type->id == TypeTableEntryIdArray) {
65537219 convert_to_const_slice = true;
65547220 }
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);
65567265 continue;
65577266 }
65587267
6559 if (cur_type->id == TypeTableEntryIdNullLit) {
6560 any_are_null = true;
6561 continue;
7268 if (prev_type->id == TypeTableEntryIdErrorUnion && cur_type->id == TypeTableEntryIdErrorUnion) {
7269 TypeTableEntry *prev_payload_type = prev_type->data.error_union.payload_type;
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 }
65627350 }
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) {
65657353 continue;
65667354 }
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) {
65697357 prev_inst = cur_inst;
65707358 continue;
65717359 }
......@@ -6588,26 +7376,41 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
65887376 }
65897377
65907378 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)
65927380 {
65937381 continue;
65947382 }
65957383
65967384 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)
65987386 {
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 }
65997402 prev_inst = cur_inst;
66007403 continue;
66017404 }
66027405
66037406 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)
66057408 {
66067409 continue;
66077410 }
66087411
66097412 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)
66117414 {
66127415 prev_inst = cur_inst;
66137416 continue;
......@@ -6645,7 +7448,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
66457448
66467449 if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray &&
66477450 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)
66497452 {
66507453 convert_to_const_slice = true;
66517454 prev_inst = cur_inst;
......@@ -6654,7 +7457,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
66547457
66557458 if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray &&
66567459 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)
66587461 {
66597462 convert_to_const_slice = true;
66607463 continue;
......@@ -6663,8 +7466,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
66637466 if (cur_type->id == TypeTableEntryIdArray && is_slice(prev_type) &&
66647467 (prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const ||
66657468 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,
6667 cur_type->data.array.child_type))
7469 types_match_const_cast_only(ira, prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
7470 cur_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
66687471 {
66697472 convert_to_const_slice = false;
66707473 continue;
......@@ -6673,8 +7476,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
66737476 if (prev_type->id == TypeTableEntryIdArray && is_slice(cur_type) &&
66747477 (cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const ||
66757478 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,
6677 prev_type->data.array.child_type))
7479 types_match_const_cast_only(ira, cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
7480 prev_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
66787481 {
66797482 prev_inst = cur_inst;
66807483 convert_to_const_slice = false;
......@@ -6714,30 +7517,37 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
67147517
67157518 return ira->codegen->builtin_types.entry_invalid;
67167519 }
7520
7521 free(errors);
7522
67177523 if (convert_to_const_slice) {
67187524 assert(prev_inst->value.type->id == TypeTableEntryIdArray);
67197525 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, prev_inst->value.type->data.array.child_type, true);
67207526 TypeTableEntry *slice_type = get_slice_type(ira->codegen, ptr_type);
6721 if (any_are_pure_error) {
6722 return get_error_type(ira->codegen, slice_type);
7527 if (err_set_type != nullptr) {
7528 return get_error_union_type(ira->codegen, err_set_type, slice_type);
67237529 } else {
67247530 return slice_type;
67257531 }
6726 } else if (any_are_pure_error && prev_inst->value.type->id != TypeTableEntryIdPureError) {
6727 if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||
6728 prev_inst->value.type->id == TypeTableEntryIdNumLitFloat)
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;
7532 } else if (err_set_type != nullptr) {
7533 if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) {
7534 return err_set_type;
67397535 } 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 }
67417551 }
67427552 } else if (any_are_null && prev_inst->value.type->id != TypeTableEntryIdNullLit) {
67437553 if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||
......@@ -6783,6 +7593,8 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
67837593 switch (cast_op) {
67847594 case CastOpNoCast:
67857595 zig_unreachable();
7596 case CastOpErrSet:
7597 zig_panic("TODO");
67867598 case CastOpNoop:
67877599 {
67887600 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
72138025 assert(wanted_type->id == TypeTableEntryIdErrorUnion);
72148026
72158027 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;
72178029 IrInstruction *casted_payload = ir_implicit_cast(ira, value, payload_type);
72188030 if (type_is_invalid(casted_payload->value.type))
72198031 return ira->codegen->invalid_instruction;
......@@ -7238,19 +8050,64 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction
72388050 return result;
72398051}
72408052
7241static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {
7242 assert(wanted_type->id == TypeTableEntryIdErrorUnion);
8053static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
8054 TypeTableEntry *wanted_type)
8055{
8056 assert(value->value.type->id == TypeTableEntryIdErrorSet);
8057 assert(wanted_type->id == TypeTableEntryIdErrorSet);
72438058
72448059 if (instr_is_comptime(value)) {
72458060 ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
72468061 if (!val)
72478062 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
72498083 IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
72508084 source_instr->scope, source_instr->source_node);
72518085 const_instruction->base.value.type = wanted_type;
72528086 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;
72548111 const_instruction->base.value.data.x_err_union.payload = nullptr;
72558112 return &const_instruction->base;
72568113 }
......@@ -7630,36 +8487,68 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction
76308487 return result;
76318488}
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{
76348493 assert(target->value.type->id == TypeTableEntryIdInt);
76358494 assert(!target->value.type->data.integral.is_signed);
8495 assert(wanted_type->id == TypeTableEntryIdErrorSet);
76368496
76378497 if (instr_is_comptime(target)) {
76388498 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
76398499 if (!val)
76408500 return ira->codegen->invalid_instruction;
76418501
7642 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
7643 source_instr->source_node, ira->codegen->builtin_types.entry_pure_error);
8502 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
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;
7646 bigint_init_unsigned(&err_count, ira->codegen->error_decls.length);
7647 if (bigint_cmp_zero(&val->data.x_bigint) == CmpEQ || bigint_cmp(&val->data.x_bigint, &err_count) != CmpLT) {
7648 Buf *val_buf = buf_alloc();
7649 bigint_append_buf(val_buf, &val->data.x_bigint, 10);
7650 ir_add_error(ira, source_instr,
7651 buf_sprintf("integer value %s represents no error", buf_ptr(val_buf)));
7652 return ira->codegen->invalid_instruction;
7653 }
8537 if (err == nullptr) {
8538 Buf *val_buf = buf_alloc();
8539 bigint_append_buf(val_buf, &val->data.x_bigint, 10);
8540 ir_add_error(ira, source_instr,
8541 buf_sprintf("integer value %s represents no error in '%s'", buf_ptr(val_buf), buf_ptr(&wanted_type->name)));
8542 return ira->codegen->invalid_instruction;
8543 }
76548544
7655 size_t index = bigint_as_unsigned(&val->data.x_bigint);
7656 AstNode *error_decl_node = ira->codegen->error_decls.at(index);
7657 result->value.data.x_pure_err = error_decl_node->data.error_value_decl.err;
7658 return result;
8545 result->value.data.x_err_set = err;
8546 return result;
8547 }
76598548 }
76608549
76618550 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;
76638552 return result;
76648553}
76658554
......@@ -7681,8 +8570,8 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
76818570 ErrorTableEntry *err;
76828571 if (err_type->id == TypeTableEntryIdErrorUnion) {
76838572 err = val->data.x_err_union.err;
7684 } else if (err_type->id == TypeTableEntryIdPureError) {
7685 err = val->data.x_pure_err;
8573 } else if (err_type->id == TypeTableEntryIdErrorSet) {
8574 err = val->data.x_err_set;
76868575 } else {
76878576 zig_unreachable();
76888577 }
......@@ -7702,8 +8591,36 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
77028591 return result;
77038592 }
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
77058622 BigInt bn;
7706 bigint_init_unsigned(&bn, ira->codegen->error_decls.length);
8623 bigint_init_unsigned(&bn, ira->codegen->errors_by_index.length);
77078624 if (!bigint_fits_in_bits(&bn, wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) {
77088625 ir_add_error_node(ira, source_instr->source_node,
77098626 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
77198636 TypeTableEntry *wanted_type, IrInstruction *value)
77208637{
77218638 TypeTableEntry *actual_type = value->value.type;
8639 AstNode *source_node = source_instr->source_node;
77228640
77238641 if (type_is_invalid(wanted_type) || type_is_invalid(actual_type)) {
77248642 return ira->codegen->invalid_instruction;
......@@ -7728,7 +8646,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
77288646 return value;
77298647
77308648 // 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) {
77328650 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
77338651 }
77348652
......@@ -7748,6 +8666,13 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
77488666 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
77498667 }
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
77518676 // explicit cast from int to float
77528677 if (wanted_type->id == TypeTableEntryIdFloat &&
77538678 actual_type->id == TypeTableEntryIdInt)
......@@ -7767,7 +8692,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
77678692 TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
77688693 assert(ptr_type->id == TypeTableEntryIdPointer);
77698694 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)
77718696 {
77728697 return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
77738698 }
......@@ -7785,7 +8710,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
77858710 TypeTableEntry *array_type = actual_type->data.pointer.child_type;
77868711
77878712 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)
77898714 {
77908715 return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
77918716 }
......@@ -7801,7 +8726,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
78018726 wanted_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;
78028727 assert(ptr_type->id == TypeTableEntryIdPointer);
78038728 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)
78058730 {
78068731 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);
78078732 if (type_is_invalid(cast1->value.type))
......@@ -7824,7 +8749,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
78248749 wanted_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;
78258750 assert(ptr_type->id == TypeTableEntryIdPointer);
78268751 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)
78288753 {
78298754 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value);
78308755 if (type_is_invalid(cast1->value.type))
......@@ -7886,7 +8811,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
78868811
78878812 // explicit cast from child type of maybe type to maybe type
78888813 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) {
78908815 return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
78918816 } else if (actual_type->id == TypeTableEntryIdNumLitInt ||
78928817 actual_type->id == TypeTableEntryIdNumLitFloat)
......@@ -7908,12 +8833,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
79088833
79098834 // explicit cast from child type of error type to error type
79108835 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) {
79128837 return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
79138838 } else if (actual_type->id == TypeTableEntryIdNumLitInt ||
79148839 actual_type->id == TypeTableEntryIdNumLitFloat)
79158840 {
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)) {
79178842 return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
79188843 } else {
79198844 return ira->codegen->invalid_instruction;
......@@ -7923,16 +8848,16 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
79238848
79248849 // explicit cast from [N]T to %[]const T
79258850 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
7926 is_slice(wanted_type->data.error.child_type) &&
8851 is_slice(wanted_type->data.error_union.payload_type) &&
79278852 actual_type->id == TypeTableEntryIdArray)
79288853 {
79298854 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;
79318856 assert(ptr_type->id == TypeTableEntryIdPointer);
79328857 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)
79348859 {
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);
79368861 if (type_is_invalid(cast1->value.type))
79378862 return ira->codegen->invalid_instruction;
79388863
......@@ -7944,25 +8869,25 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
79448869 }
79458870 }
79468871
7947 // explicit cast from pure error to error union type
8872 // explicit cast from error set to error union type
79488873 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
7949 actual_type->id == TypeTableEntryIdPureError)
8874 actual_type->id == TypeTableEntryIdErrorSet)
79508875 {
79518876 return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type);
79528877 }
79538878
79548879 // explicit cast from T to %?T
79558880 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
7956 wanted_type->data.error.child_type->id == TypeTableEntryIdMaybe &&
8881 wanted_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe &&
79578882 actual_type->id != TypeTableEntryIdMaybe)
79588883 {
7959 TypeTableEntry *wanted_child_type = wanted_type->data.error.child_type->data.maybe.child_type;
7960 if (types_match_const_cast_only(wanted_child_type, actual_type) ||
8884 TypeTableEntry *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type;
8885 if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node).id == ConstCastResultIdOk ||
79618886 actual_type->id == TypeTableEntryIdNullLit ||
79628887 actual_type->id == TypeTableEntryIdNumLitInt ||
79638888 actual_type->id == TypeTableEntryIdNumLitFloat)
79648889 {
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);
79668891 if (type_is_invalid(cast1->value.type))
79678892 return ira->codegen->invalid_instruction;
79688893
......@@ -8031,21 +8956,19 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
80318956 return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type);
80328957 }
80338958
8034 // explicit cast from %void to integer type which can fit it
8959 // explicit cast from T!void to integer type which can fit it
80358960 bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion &&
8036 !type_has_bits(actual_type->data.error.child_type);
8037 bool actual_type_is_pure_err = actual_type->id == TypeTableEntryIdPureError;
8038 if ((actual_type_is_void_err || actual_type_is_pure_err) &&
8039 wanted_type->id == TypeTableEntryIdInt)
8040 {
8961 !type_has_bits(actual_type->data.error_union.payload_type);
8962 bool actual_type_is_err_set = actual_type->id == TypeTableEntryIdErrorSet;
8963 if ((actual_type_is_void_err || actual_type_is_err_set) && wanted_type->id == TypeTableEntryIdInt) {
80418964 return ir_analyze_err_to_int(ira, source_instr, value, wanted_type);
80428965 }
80438966
8044 // explicit cast from integer to pure error
8045 if (wanted_type->id == TypeTableEntryIdPureError && actual_type->id == TypeTableEntryIdInt &&
8967 // explicit cast from integer to error set
8968 if (wanted_type->id == TypeTableEntryIdErrorSet && actual_type->id == TypeTableEntryIdInt &&
80468969 !actual_type->data.integral.is_signed)
80478970 {
8048 return ir_analyze_int_to_err(ira, source_instr, value);
8971 return ir_analyze_int_to_err(ira, source_instr, value, wanted_type);
80498972 }
80508973
80518974 // explicit cast from integer to enum type with no payload
......@@ -8109,7 +9032,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
81099032 // explicit cast from something to const pointer of it
81109033 if (!type_requires_comptime(actual_type)) {
81119034 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) {
81139036 return ir_analyze_cast_ref(ira, source_instr, value, wanted_type);
81149037 }
81159038 }
......@@ -8471,6 +9394,7 @@ static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) {
84719394static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
84729395 IrInstruction *op1 = bin_op_instruction->op1->other;
84739396 IrInstruction *op2 = bin_op_instruction->op2->other;
9397 AstNode *source_node = bin_op_instruction->base.source_node;
84749398
84759399 IrBinOp op_id = bin_op_instruction->op_id;
84769400 bool is_equality_cmp = (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq);
......@@ -8503,7 +9427,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
85039427 }
85049428
85059429 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);
85079431 is_non_null->value.type = ira->codegen->builtin_types.entry_bool;
85089432
85099433 if (op_id == IrBinOpCmpEq) {
......@@ -8514,8 +9438,88 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
85149438 return ira->codegen->builtin_types.entry_bool;
85159439 }
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
85179521 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);
85199523 if (type_is_invalid(resolved_type))
85209524 return resolved_type;
85219525 type_ensure_zero_bits_known(ira->codegen, resolved_type);
......@@ -8523,7 +9527,6 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
85239527 return resolved_type;
85249528
85259529
8526 AstNode *source_node = bin_op_instruction->base.source_node;
85279530 switch (resolved_type->id) {
85289531 case TypeTableEntryIdInvalid:
85299532 zig_unreachable(); // handled above
......@@ -8538,7 +9541,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
85389541 case TypeTableEntryIdMetaType:
85399542 case TypeTableEntryIdVoid:
85409543 case TypeTableEntryIdPointer:
8541 case TypeTableEntryIdPureError:
9544 case TypeTableEntryIdErrorSet:
85429545 case TypeTableEntryIdFn:
85439546 case TypeTableEntryIdOpaque:
85449547 case TypeTableEntryIdNamespace:
......@@ -8692,6 +9695,7 @@ static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val,
86929695 case IrBinOpArrayCat:
86939696 case IrBinOpArrayMult:
86949697 case IrBinOpRemUnspecified:
9698 case IrBinOpMergeErrorSets:
86959699 zig_unreachable();
86969700 case IrBinOpBinOr:
86979701 assert(is_int);
......@@ -9264,6 +10268,46 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp
926410268 return get_array_type(ira->codegen, child_type, new_array_len);
926510269}
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
926710311static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
926810312 IrBinOp op_id = bin_op_instruction->op_id;
926910313 switch (op_id) {
......@@ -9305,6 +10349,8 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi
930510349 return ir_analyze_array_cat(ira, bin_op_instruction);
930610350 case IrBinOpArrayMult:
930710351 return ir_analyze_array_mult(ira, bin_op_instruction);
10352 case IrBinOpMergeErrorSets:
10353 return ir_analyze_merge_error_sets(ira, bin_op_instruction);
930810354 }
930910355 zig_unreachable();
931010356}
......@@ -9326,7 +10372,7 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) {
932610372 case TypeTableEntryIdInt:
932710373 case TypeTableEntryIdFloat:
932810374 case TypeTableEntryIdVoid:
9329 case TypeTableEntryIdPureError:
10375 case TypeTableEntryIdErrorSet:
933010376 case TypeTableEntryIdFn:
933110377 return VarClassRequiredAny;
933210378 case TypeTableEntryIdNumLitFloat:
......@@ -9352,7 +10398,7 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) {
935210398 case TypeTableEntryIdMaybe:
935310399 return get_var_class_required(type_entry->data.maybe.child_type);
935410400 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
935710403 case TypeTableEntryIdStruct:
935810404 case TypeTableEntryIdEnum:
......@@ -9587,7 +10633,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
958710633 case TypeTableEntryIdNullLit:
958810634 case TypeTableEntryIdMaybe:
958910635 case TypeTableEntryIdErrorUnion:
9590 case TypeTableEntryIdPureError:
10636 case TypeTableEntryIdErrorSet:
959110637 case TypeTableEntryIdNamespace:
959210638 case TypeTableEntryIdBlock:
959310639 case TypeTableEntryIdBoundFn:
......@@ -9610,7 +10656,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
961010656 case TypeTableEntryIdNullLit:
961110657 case TypeTableEntryIdMaybe:
961210658 case TypeTableEntryIdErrorUnion:
9613 case TypeTableEntryIdPureError:
10659 case TypeTableEntryIdErrorSet:
961410660 zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name));
961510661 case TypeTableEntryIdNamespace:
961610662 case TypeTableEntryIdBlock:
......@@ -9644,6 +10690,31 @@ static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
964410690 return nullable_type;
964510691}
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
964710718static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
964810719 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)
964910720{
......@@ -9926,9 +10997,17 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
992610997 }
992710998
992810999 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);
9930 if (type_is_invalid(return_type))
11000 TypeTableEntry *specified_return_type = analyze_type_expr(ira->codegen, exec_scope, return_type_node);
11001 if (type_is_invalid(specified_return_type))
993111002 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
993311012 IrInstruction *result;
993411013
......@@ -9942,6 +11021,23 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
994211021 ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry,
994311022 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
994511041 ira->codegen->memoized_fn_eval_table.put(exec_scope, result);
994611042
994711043 if (type_is_invalid(result->value.type))
......@@ -10092,12 +11188,17 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1009211188
1009311189 {
1009411190 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);
10096 if (type_is_invalid(return_type))
11191 TypeTableEntry *specified_return_type = analyze_type_expr(ira->codegen, impl_fn->child_scope, return_type_node);
11192 if (type_is_invalid(specified_return_type))
1009711193 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)) {
1010111202 // Throw out our work and call the function as if it were comptime.
1010211203 return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, FnInlineAuto);
1010311204 }
......@@ -10128,7 +11229,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1012811229 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
1012911230 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) {
1013211233 parent_fn_entry->calls_errorable_function = true;
1013311234 }
1013411235
......@@ -10138,7 +11239,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1013811239 FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
1013911240 assert(fn_type_id->return_type != nullptr);
1014011241 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) {
1014211243 parent_fn_entry->calls_errorable_function = true;
1014311244 }
1014411245
......@@ -10257,58 +11358,6 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
1025711358 }
1025811359}
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
1031211361static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
1031311362 IrInstruction *value = un_op_instruction->value->other;
1031411363
......@@ -10364,7 +11413,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
1036411413 case TypeTableEntryIdNullLit:
1036511414 case TypeTableEntryIdMaybe:
1036611415 case TypeTableEntryIdErrorUnion:
10367 case TypeTableEntryIdPureError:
11416 case TypeTableEntryIdErrorSet:
1036811417 case TypeTableEntryIdEnum:
1036911418 case TypeTableEntryIdUnion:
1037011419 case TypeTableEntryIdFn:
......@@ -10474,8 +11523,6 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio
1047411523 return ir_analyze_dereference(ira, un_op_instruction);
1047511524 case IrUnOpMaybe:
1047611525 return ir_analyze_maybe(ira, un_op_instruction);
10477 case IrUnOpError:
10478 return ir_analyze_unary_prefix_op_err(ira, un_op_instruction);
1047911526 }
1048011527 zig_unreachable();
1048111528}
......@@ -10633,6 +11680,9 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
1063311680 IrInstruction *branch_instruction = predecessor->instruction_list.pop();
1063411681 ir_set_cursor_at_end(&ira->new_irb, predecessor);
1063511682 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 }
1063611686 new_incoming_values.items[i] = casted_value;
1063711687 predecessor->instruction_list.append(branch_instruction);
1063811688
......@@ -11048,6 +12098,25 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
1104812098 }
1104912099}
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
1105112120static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) {
1105212121 bool pointer_only = false;
1105312122 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
1106312132 TldVar *tld_var = (TldVar *)tld;
1106412133 VariableTableEntry *var = tld_var->var;
1106512134 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);
1106712136 }
1106812137
1106912138 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
1108512154 const_val->data.x_fn.fn_entry = fn_entry;
1108612155
1108712156 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);
1108912158 }
1109012159
1109112160 bool ptr_is_const = true;
......@@ -11097,6 +12166,17 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
1109712166 zig_unreachable();
1109812167}
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
1110012180static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstructionFieldPtr *field_ptr_instruction) {
1110112181 IrInstruction *container_ptr = field_ptr_instruction->container_ptr->other;
1110212182 if (type_is_invalid(container_ptr->value.type))
......@@ -11238,23 +12318,52 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1123812318 buf_sprintf("container '%s' has no member called '%s'",
1123912319 buf_ptr(&child_type->name), buf_ptr(field_name)));
1124012320 return ira->codegen->builtin_types.entry_invalid;
11241 } else if (child_type->id == TypeTableEntryIdPureError) {
11242 auto err_table_entry = ira->codegen->error_table.maybe_get(field_name);
11243 if (err_table_entry) {
11244 ConstExprValue *const_val = create_const_vals(1);
11245 const_val->special = ConstValSpecialStatic;
11246 const_val->type = child_type;
11247 const_val->data.x_pure_err = err_table_entry->value;
11248
11249 bool ptr_is_const = true;
11250 bool ptr_is_volatile = false;
11251 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val,
11252 child_type, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
12321 } else if (child_type->id == TypeTableEntryIdErrorSet) {
12322 ErrorTableEntry *err_entry;
12323 TypeTableEntry *err_set_type;
12324 if (type_is_global_error_set(child_type)) {
12325 auto existing_entry = ira->codegen->error_table.maybe_get(field_name);
12326 if (existing_entry) {
12327 err_entry = existing_entry->value;
12328 } else {
12329 err_entry = allocate<ErrorTableEntry>(1);
12330 err_entry->decl_node = field_ptr_instruction->base.source_node;
12331 buf_init_from_buf(&err_entry->name, field_name);
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;
1125312357 }
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,
11256 buf_sprintf("use of undeclared error value '%s'", buf_ptr(field_name)));
11257 return ira->codegen->builtin_types.entry_invalid;
12363 bool ptr_is_const = true;
12364 bool ptr_is_volatile = false;
12365 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val,
12366 err_set_type, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
1125812367 } else if (child_type->id == TypeTableEntryIdInt) {
1125912368 if (buf_eql_str(field_name, "bit_count")) {
1126012369 bool ptr_is_const = true;
......@@ -11337,11 +12446,18 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1133712446 return ira->codegen->builtin_types.entry_invalid;
1133812447 }
1133912448 } 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")) {
1134112457 bool ptr_is_const = true;
1134212458 bool ptr_is_volatile = false;
1134312459 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),
1134512461 ira->codegen->builtin_types.entry_type,
1134612462 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
1134712463 } else {
......@@ -11528,7 +12644,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
1152812644 case TypeTableEntryIdStruct:
1152912645 case TypeTableEntryIdMaybe:
1153012646 case TypeTableEntryIdErrorUnion:
11531 case TypeTableEntryIdPureError:
12647 case TypeTableEntryIdErrorSet:
1153212648 case TypeTableEntryIdEnum:
1153312649 case TypeTableEntryIdUnion:
1153412650 case TypeTableEntryIdFn:
......@@ -11795,7 +12911,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
1179512911 case TypeTableEntryIdNumLitInt:
1179612912 case TypeTableEntryIdMaybe:
1179712913 case TypeTableEntryIdErrorUnion:
11798 case TypeTableEntryIdPureError:
12914 case TypeTableEntryIdErrorSet:
1179912915 case TypeTableEntryIdEnum:
1180012916 case TypeTableEntryIdUnion:
1180112917 case TypeTableEntryIdFn:
......@@ -11903,7 +13019,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
1190313019 case TypeTableEntryIdNumLitInt:
1190413020 case TypeTableEntryIdMaybe:
1190513021 case TypeTableEntryIdErrorUnion:
11906 case TypeTableEntryIdPureError:
13022 case TypeTableEntryIdErrorSet:
1190713023 case TypeTableEntryIdEnum:
1190813024 case TypeTableEntryIdUnion:
1190913025 case TypeTableEntryIdFn:
......@@ -11956,7 +13072,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
1195613072 case TypeTableEntryIdStruct:
1195713073 case TypeTableEntryIdMaybe:
1195813074 case TypeTableEntryIdErrorUnion:
11959 case TypeTableEntryIdPureError:
13075 case TypeTableEntryIdErrorSet:
1196013076 case TypeTableEntryIdEnum:
1196113077 case TypeTableEntryIdUnion:
1196213078 case TypeTableEntryIdFn:
......@@ -12291,7 +13407,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
1229113407 case TypeTableEntryIdPointer:
1229213408 case TypeTableEntryIdFn:
1229313409 case TypeTableEntryIdNamespace:
12294 case TypeTableEntryIdPureError:
13410 case TypeTableEntryIdErrorSet:
1229513411 if (pointee_val) {
1229613412 ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);
1229713413 copy_const_val(out_val, pointee_val, true);
......@@ -12361,8 +13477,6 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
1236113477 return target_type;
1236213478 }
1236313479 case TypeTableEntryIdErrorUnion:
12364 // see https://github.com/andrewrk/zig/issues/632
12365 zig_panic("TODO switch on error union");
1236613480 case TypeTableEntryIdUnreachable:
1236713481 case TypeTableEntryIdArray:
1236813482 case TypeTableEntryIdStruct:
......@@ -12887,7 +14001,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
1288714001 case TypeTableEntryIdNullLit:
1288814002 case TypeTableEntryIdMaybe:
1288914003 case TypeTableEntryIdErrorUnion:
12890 case TypeTableEntryIdPureError:
14004 case TypeTableEntryIdErrorSet:
1289114005 case TypeTableEntryIdUnion:
1289214006 case TypeTableEntryIdFn:
1289314007 case TypeTableEntryIdNamespace:
......@@ -12975,7 +14089,7 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc
1297514089 TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
1297614090 TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type);
1297714091 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;
1297914093 if (!err->cached_error_name_val) {
1298014094 ConstExprValue *array_val = create_const_str_lit(ira->codegen, &err->name);
1298114095 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
1395615070 result = container_type->data.structure.src_field_count;
1395715071 } else if (container_type->id == TypeTableEntryIdUnion) {
1395815072 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;
1395915082 } else {
1396015083 ir_add_error(ira, &instruction->base, buf_sprintf("no value count available for type '%s'", buf_ptr(&container_type->name)));
1396115084 return ira->codegen->builtin_types.entry_invalid;
......@@ -14120,7 +15243,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc
1412015243 case TypeTableEntryIdStruct:
1412115244 case TypeTableEntryIdMaybe:
1412215245 case TypeTableEntryIdErrorUnion:
14123 case TypeTableEntryIdPureError:
15246 case TypeTableEntryIdErrorSet:
1412415247 case TypeTableEntryIdEnum:
1412515248 case TypeTableEntryIdUnion:
1412615249 case TypeTableEntryIdFn:
......@@ -14251,9 +15374,22 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc
1425115374 }
1425215375 }
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
1425415390 ir_build_test_err_from(&ira->new_irb, &instruction->base, value);
1425515391 return ira->codegen->builtin_types.entry_bool;
14256 } else if (type_entry->id == TypeTableEntryIdPureError) {
15392 } else if (type_entry->id == TypeTableEntryIdErrorSet) {
1425715393 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
1425815394 out_val->data.x_bool = true;
1425915395 return ira->codegen->builtin_types.entry_bool;
......@@ -14289,13 +15425,13 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira,
1428915425 assert(err);
1429015426
1429115427 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
14292 out_val->data.x_pure_err = err;
14293 return ira->codegen->builtin_types.entry_pure_error;
15428 out_val->data.x_err_set = err;
15429 return type_entry->data.error_union.err_set_type;
1429415430 }
1429515431 }
1429615432
1429715433 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;
1429915435 } else {
1430015436 ir_add_error(ira, value,
1430115437 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,
1431915455 if (type_is_invalid(type_entry)) {
1432015456 return ira->codegen->builtin_types.entry_invalid;
1432115457 } else if (type_entry->id == TypeTableEntryIdErrorUnion) {
14322 TypeTableEntry *child_type = type_entry->data.error.child_type;
14323 TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
15458 TypeTableEntry *payload_type = type_entry->data.error_union.payload_type;
15459 TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, payload_type,
1432415460 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);
1432615462 if (instr_is_comptime(value)) {
1432715463 ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
1432815464 if (!ptr_val)
......@@ -14332,7 +15468,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
1433215468 ErrorTableEntry *err = err_union_val->data.x_err_union.err;
1433315469 if (err != nullptr) {
1433415470 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)));
1433615472 return ira->codegen->builtin_types.entry_invalid;
1433715473 }
1433815474
......@@ -14357,6 +15493,12 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
1435715493 AstNode *proto_node = instruction->base.source_node;
1435815494 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
1436015502 FnTypeId fn_type_id = {0};
1436115503 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
1448215624 }
1448315625 }
1448415626 }
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);
1448515678 } else if (switch_type->id == TypeTableEntryIdInt) {
1448615679 RangeSet rs = {0};
1448715680 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
1477415967 zig_panic("TODO buf_write_value_bytes maybe type");
1477515968 case TypeTableEntryIdErrorUnion:
1477615969 zig_panic("TODO buf_write_value_bytes error union");
14777 case TypeTableEntryIdPureError:
15970 case TypeTableEntryIdErrorSet:
1477815971 zig_panic("TODO buf_write_value_bytes pure error type");
1477915972 case TypeTableEntryIdEnum:
1478015973 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
1483216025 zig_panic("TODO buf_read_value_bytes maybe type");
1483316026 case TypeTableEntryIdErrorUnion:
1483416027 zig_panic("TODO buf_read_value_bytes error union");
14835 case TypeTableEntryIdPureError:
16028 case TypeTableEntryIdErrorSet:
1483616029 zig_panic("TODO buf_read_value_bytes pure error type");
1483716030 case TypeTableEntryIdEnum:
1483816031 zig_panic("TODO buf_read_value_bytes enum type");
......@@ -15010,7 +16203,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
1501016203 return ira->codegen->builtin_types.entry_invalid;
1501116204
1501216205 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);
1501416207 }
1501516208
1501616209 if (lval.is_ptr) {
......@@ -15029,7 +16222,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
1502916222 assert(fn_entry->type_entry);
1503016223
1503116224 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);
1503316226 }
1503416227
1503516228 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
1544316636 return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction);
1544416637 case IrInstructionIdErrorReturnTrace:
1544516638 return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction);
16639 case IrInstructionIdErrorUnion:
16640 return ir_analyze_instruction_error_union(ira, (IrInstructionErrorUnion *)instruction);
1544616641 }
1544716642 zig_unreachable();
1544816643}
......@@ -15628,6 +16823,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1562816823 case IrInstructionIdArgType:
1562916824 case IrInstructionIdTagType:
1563016825 case IrInstructionIdErrorReturnTrace:
16826 case IrInstructionIdErrorUnion:
1563116827 return false;
1563216828 case IrInstructionIdAsm:
1563316829 {
src/ir_print.cpp+10-2
......@@ -130,6 +130,8 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) {
130130 return "++";
131131 case IrBinOpArrayMult:
132132 return "**";
133 case IrBinOpMergeErrorSets:
134 return "||";
133135 }
134136 zig_unreachable();
135137}
......@@ -148,8 +150,6 @@ static const char *ir_un_op_id_str(IrUnOp op_id) {
148150 return "*";
149151 case IrUnOpMaybe:
150152 return "?";
151 case IrUnOpError:
152 return "%";
153153 }
154154 zig_unreachable();
155155}
......@@ -1004,6 +1004,11 @@ static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTr
10041004 fprintf(irp->f, "@errorReturnTrace()");
10051005}
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
10081013static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
10091014 ir_print_prefix(irp, instruction);
......@@ -1322,6 +1327,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
13221327 case IrInstructionIdErrorReturnTrace:
13231328 ir_print_error_return_trace(irp, (IrInstructionErrorReturnTrace *)instruction);
13241329 break;
1330 case IrInstructionIdErrorUnion:
1331 ir_print_error_union(irp, (IrInstructionErrorUnion *)instruction);
1332 break;
13251333 }
13261334 fprintf(irp->f, "\n");
13271335}
src/main.cpp+8
......@@ -66,6 +66,7 @@ static int usage(const char *arg0) {
6666 " --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides\n"
6767 " --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides\n"
6868 " --library [lib] link against lib\n"
69 " --forbid-library [lib] make it an error to link against lib\n"
6970 " --library-path [dir] add a directory to the library search path\n"
7071 " --linker-script [path] use a custom linker script\n"
7172 " --object [obj] add object file to build\n"
......@@ -309,6 +310,7 @@ int main(int argc, char **argv) {
309310 ZigList<const char *> llvm_argv = {0};
310311 ZigList<const char *> lib_dirs = {0};
311312 ZigList<const char *> link_libs = {0};
313 ZigList<const char *> forbidden_link_libs = {0};
312314 ZigList<const char *> frameworks = {0};
313315 int err;
314316 const char *target_arch = nullptr;
......@@ -605,6 +607,8 @@ int main(int argc, char **argv) {
605607 lib_dirs.append(argv[i]);
606608 } else if (strcmp(arg, "--library") == 0) {
607609 link_libs.append(argv[i]);
610 } else if (strcmp(arg, "--forbid-library") == 0) {
611 forbidden_link_libs.append(argv[i]);
608612 } else if (strcmp(arg, "--object") == 0) {
609613 objects.append(argv[i]);
610614 } else if (strcmp(arg, "--assembly") == 0) {
......@@ -817,6 +821,10 @@ int main(int argc, char **argv) {
817821 LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i)));
818822 link_lib->provided_explicitly = true;
819823 }
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 }
820828 for (size_t i = 0; i < frameworks.length; i += 1) {
821829 codegen_add_framework(g, frameworks.at(i));
822830 }
src/parser.cpp+74-42
......@@ -221,6 +221,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, size_t *token_index, bo
221221static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory);
222222static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory);
223223static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index);
224static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index);
224225
225226static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
226227 if (token->id == token_id) {
......@@ -240,7 +241,28 @@ static Token *ast_eat_token(ParseContext *pc, size_t *token_index, TokenId token
240241}
241242
242243/*
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"
244266*/
245267static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
246268 Token *token = &pc->tokens->at(*token_index);
......@@ -249,7 +271,7 @@ static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool
249271 *token_index += 1;
250272 return node;
251273 } else {
252 return ast_parse_prefix_op_expr(pc, token_index, mandatory);
274 return ast_parse_error_set_expr(pc, token_index, mandatory);
253275 }
254276}
255277
......@@ -651,8 +673,9 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b
651673}
652674
653675/*
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
655677KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable"
678ErrorSetDecl = "error" "{" list(Symbol, ",") "}"
656679*/
657680static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
658681 Token *token = &pc->tokens->at(*token_index);
......@@ -716,9 +739,31 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
716739 *token_index += 1;
717740 return node;
718741 } else if (token->id == TokenIdKeywordError) {
719 AstNode *node = ast_create_node(pc, NodeTypeErrorType, token);
720 *token_index += 1;
721 return node;
742 Token *next_token = &pc->tokens->at(*token_index + 1);
743 if (next_token->id == TokenIdLBrace) {
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 }
722767 } else if (token->id == TokenIdAtSign) {
723768 *token_index += 1;
724769 Token *name_tok = &pc->tokens->at(*token_index);
......@@ -950,7 +995,6 @@ static PrefixOp tok_to_prefix_op(Token *token) {
950995 case TokenIdTilde: return PrefixOpBinNot;
951996 case TokenIdStar: return PrefixOpDereference;
952997 case TokenIdMaybe: return PrefixOpMaybe;
953 case TokenIdPercent: return PrefixOpError;
954998 case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe;
955999 case TokenIdStarStar: return PrefixOpDereference;
9561000 default: return PrefixOpInvalid;
......@@ -997,8 +1041,8 @@ static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) {
9971041}
9981042
9991043/*
1000PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression
1001PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%" | "try"
1044PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression
1045PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try"
10021046*/
10031047static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
10041048 Token *token = &pc->tokens->at(*token_index);
......@@ -1028,7 +1072,7 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index,
10281072 node->column += 1;
10291073 }
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);
10321076 node->data.prefix_op_expr.primary_expr = prefix_op_expr;
10331077 node->data.prefix_op_expr.prefix_op = prefix_op;
10341078
......@@ -1043,12 +1087,14 @@ static BinOpType tok_to_mult_op(Token *token) {
10431087 case TokenIdStarStar: return BinOpTypeArrayMult;
10441088 case TokenIdSlash: return BinOpTypeDiv;
10451089 case TokenIdPercent: return BinOpTypeMod;
1090 case TokenIdBang: return BinOpTypeErrorUnion;
1091 case TokenIdBarBar: return BinOpTypeMergeErrorSets;
10461092 default: return BinOpTypeInvalid;
10471093 }
10481094}
10491095
10501096/*
1051MultiplyOperator = "*" | "/" | "%" | "**" | "*%"
1097MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
10521098*/
10531099static BinOpType ast_parse_mult_op(ParseContext *pc, size_t *token_index, bool mandatory) {
10541100 Token *token = &pc->tokens->at(*token_index);
......@@ -2240,7 +2286,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
22402286}
22412287
22422288/*
2243FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") TypeExpr
2289FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
22442290*/
22452291static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
22462292 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
23152361 ast_eat_token(pc, token_index, TokenIdRParen);
23162362 next_token = &pc->tokens->at(*token_index);
23172363 }
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 }
23182376 node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, true);
23192377
23202378 return node;
......@@ -2531,7 +2589,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
25312589 Token *colon_token = &pc->tokens->at(*token_index);
25322590 if (colon_token->id == TokenIdColon) {
25332591 *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);
25352593 }
25362594 Token *eq_token = &pc->tokens->at(*token_index);
25372595 if (eq_token->id == TokenIdEq) {
......@@ -2559,26 +2617,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
25592617 return node;
25602618}
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
25822620/*
25832621TestDecl = "test" String Block
25842622*/
......@@ -2611,12 +2649,6 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig
26112649 continue;
26122650 }
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
26202652 AstNode *test_decl_node = ast_parse_test_decl_node(pc, token_index);
26212653 if (test_decl_node) {
26222654 top_level_decls->append(test_decl_node);
......@@ -2744,9 +2776,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
27442776 visit_field(&node->data.variable_declaration.align_expr, visit, context);
27452777 visit_field(&node->data.variable_declaration.section_expr, visit, context);
27462778 break;
2747 case NodeTypeErrorValueDecl:
2748 // none
2749 break;
27502779 case NodeTypeTestDecl:
27512780 visit_field(&node->data.test_decl.body, visit, context);
27522781 break;
......@@ -2899,5 +2928,8 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
28992928 visit_field(&node->data.addr_of_expr.align_expr, visit, context);
29002929 visit_field(&node->data.addr_of_expr.op_expr, visit, context);
29012930 break;
2931 case NodeTypeErrorSetDecl:
2932 visit_node_list(&node->data.err_set_decl.decls, visit, context);
2933 break;
29022934 }
29032935}
src/tokenizer.cpp+25-4
......@@ -195,7 +195,8 @@ enum TokenizeState {
195195 TokenizeStateSawMinusPercent,
196196 TokenizeStateSawAmpersand,
197197 TokenizeStateSawCaret,
198 TokenizeStateSawPipe,
198 TokenizeStateSawBar,
199 TokenizeStateSawBarBar,
199200 TokenizeStateLineComment,
200201 TokenizeStateLineString,
201202 TokenizeStateLineStringEnd,
......@@ -594,7 +595,7 @@ void tokenize(Buf *buf, Tokenization *out) {
594595 break;
595596 case '|':
596597 begin_token(&t, TokenIdBinOr);
597 t.state = TokenizeStateSawPipe;
598 t.state = TokenizeStateSawBar;
598599 break;
599600 case '=':
600601 begin_token(&t, TokenIdEq);
......@@ -888,13 +889,17 @@ void tokenize(Buf *buf, Tokenization *out) {
888889 continue;
889890 }
890891 break;
891 case TokenizeStateSawPipe:
892 case TokenizeStateSawBar:
892893 switch (c) {
893894 case '=':
894895 set_token_id(&t, t.cur_tok, TokenIdBitOrEq);
895896 end_token(&t);
896897 t.state = TokenizeStateStart;
897898 break;
899 case '|':
900 set_token_id(&t, t.cur_tok, TokenIdBarBar);
901 t.state = TokenizeStateSawBarBar;
902 break;
898903 default:
899904 t.pos -= 1;
900905 end_token(&t);
......@@ -902,6 +907,19 @@ void tokenize(Buf *buf, Tokenization *out) {
902907 continue;
903908 }
904909 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 }
905923 case TokenizeStateSawSlash:
906924 switch (c) {
907925 case '/':
......@@ -1428,7 +1446,7 @@ void tokenize(Buf *buf, Tokenization *out) {
14281446 case TokenizeStateSawDash:
14291447 case TokenizeStateSawAmpersand:
14301448 case TokenizeStateSawCaret:
1431 case TokenizeStateSawPipe:
1449 case TokenizeStateSawBar:
14321450 case TokenizeStateSawEq:
14331451 case TokenizeStateSawBang:
14341452 case TokenizeStateSawLessThan:
......@@ -1443,6 +1461,7 @@ void tokenize(Buf *buf, Tokenization *out) {
14431461 case TokenizeStateSawMinusPercent:
14441462 case TokenizeStateLineString:
14451463 case TokenizeStateLineStringEnd:
1464 case TokenizeStateSawBarBar:
14461465 end_token(&t);
14471466 break;
14481467 case TokenizeStateSawDotDot:
......@@ -1475,6 +1494,7 @@ const char * token_name(TokenId id) {
14751494 case TokenIdArrow: return "->";
14761495 case TokenIdAtSign: return "@";
14771496 case TokenIdBang: return "!";
1497 case TokenIdBarBar: return "||";
14781498 case TokenIdBinOr: return "|";
14791499 case TokenIdBinXor: return "^";
14801500 case TokenIdBitAndEq: return "&=";
......@@ -1577,6 +1597,7 @@ const char * token_name(TokenId id) {
15771597 case TokenIdTimesEq: return "*=";
15781598 case TokenIdTimesPercent: return "*%";
15791599 case TokenIdTimesPercentEq: return "*%=";
1600 case TokenIdBarBarEq: return "||=";
15801601 }
15811602 return "(invalid token)";
15821603}
src/tokenizer.hpp+2
......@@ -17,6 +17,8 @@ enum TokenId {
1717 TokenIdArrow,
1818 TokenIdAtSign,
1919 TokenIdBang,
20 TokenIdBarBar,
21 TokenIdBarBarEq,
2022 TokenIdBinOr,
2123 TokenIdBinXor,
2224 TokenIdBitAndEq,
src/util.hpp+11-8
......@@ -92,19 +92,22 @@ static inline void safe_memcpy(T *dest, const T *src, size_t count) {
9292}
9393
9494template<typename T>
95static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) {
96#ifdef NDEBUG
95static inline T *reallocate(T *old, size_t old_count, size_t new_count) {
9796 T *ptr = reinterpret_cast<T*>(realloc(old, new_count * sizeof(T)));
9897 if (!ptr)
9998 zig_panic("allocation failed");
99 if (new_count > old_count) {
100 memset(&ptr[old_count], 0, (new_count - old_count) * sizeof(T));
101 }
100102 return ptr;
101#else
102 // manually assign every element to trigger compile error for non-copyable structs
103 T *ptr = allocate_nonzero<T>(new_count);
104 safe_memcpy(ptr, old, old_count);
105 free(old);
103}
104
105template<typename T>
106static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) {
107 T *ptr = reinterpret_cast<T*>(realloc(old, new_count * sizeof(T)));
108 if (!ptr)
109 zig_panic("allocation failed");
106110 return ptr;
107#endif
108111}
109112
110113template <typename T, size_t n>
src/zig_llvm.cpp+4
......@@ -437,6 +437,10 @@ unsigned ZigLLVMTag_DW_structure_type(void) {
437437 return dwarf::DW_TAG_structure_type;
438438}
439439
440unsigned ZigLLVMTag_DW_enumeration_type(void) {
441 return dwarf::DW_TAG_enumeration_type;
442}
443
440444unsigned ZigLLVMTag_DW_union_type(void) {
441445 return dwarf::DW_TAG_union_type;
442446}
src/zig_llvm.h+1
......@@ -133,6 +133,7 @@ ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_signed_char(void);
133133ZIG_EXTERN_C unsigned ZigLLVMLang_DW_LANG_C99(void);
134134ZIG_EXTERN_C unsigned ZigLLVMTag_DW_variable(void);
135135ZIG_EXTERN_C unsigned ZigLLVMTag_DW_structure_type(void);
136ZIG_EXTERN_C unsigned ZigLLVMTag_DW_enumeration_type(void);
136137ZIG_EXTERN_C unsigned ZigLLVMTag_DW_union_type(void);
137138
138139ZIG_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{
6363 return result;
6464 }
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 {
6767 try l.ensureCapacity(l.len + 1);
6868 l.len += 1;
6969
......@@ -71,7 +71,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
7171 l.items[n] = *item;
7272 }
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 {
7575 try l.ensureCapacity(l.len + items.len);
7676 l.len += items.len;
7777
......@@ -79,18 +79,18 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
7979 mem.copy(T, l.items[n..n+items.len], items);
8080 }
8181
82 pub fn append(l: &Self, item: &const T) %void {
82 pub fn append(l: &Self, item: &const T) !void {
8383 const new_item_ptr = try l.addOne();
8484 *new_item_ptr = *item;
8585 }
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 {
8888 try l.ensureCapacity(l.len + items.len);
8989 mem.copy(T, l.items[l.len..], items);
9090 l.len += items.len;
9191 }
9292
93 pub fn resize(l: &Self, new_len: usize) %void {
93 pub fn resize(l: &Self, new_len: usize) !void {
9494 try l.ensureCapacity(new_len);
9595 l.len = new_len;
9696 }
......@@ -100,7 +100,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
100100 l.len = new_len;
101101 }
102102
103 pub fn ensureCapacity(l: &Self, new_capacity: usize) %void {
103 pub fn ensureCapacity(l: &Self, new_capacity: usize) !void {
104104 var better_capacity = l.items.len;
105105 if (better_capacity >= new_capacity) return;
106106 while (true) {
......@@ -110,7 +110,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
110110 l.items = try l.allocator.alignedRealloc(T, A, l.items, better_capacity);
111111 }
112112
113 pub fn addOne(l: &Self) %&T {
113 pub fn addOne(l: &Self) !&T {
114114 const new_length = l.len + 1;
115115 try l.ensureCapacity(new_length);
116116 const result = &l.items[l.len];
std/base64.zig+11-16
......@@ -79,8 +79,6 @@ pub const Base64Encoder = struct {
7979};
8080
8181pub const standard_decoder = Base64Decoder.init(standard_alphabet_chars, standard_pad_char);
82error InvalidPadding;
83error InvalidCharacter;
8482
8583pub const Base64Decoder = struct {
8684 /// e.g. 'A' => 0.
......@@ -111,7 +109,7 @@ pub const Base64Decoder = struct {
111109 }
112110
113111 /// 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 {
115113 if (source.len % 4 != 0) return error.InvalidPadding;
116114 return calcDecodedSizeExactUnsafe(source, decoder.pad_char);
117115 }
......@@ -119,7 +117,7 @@ pub const Base64Decoder = struct {
119117 /// dest.len must be what you get from ::calcSize.
120118 /// invalid characters result in error.InvalidCharacter.
121119 /// 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 {
123121 assert(dest.len == (decoder.calcSize(source) catch unreachable));
124122 assert(source.len % 4 == 0);
125123
......@@ -163,8 +161,6 @@ pub const Base64Decoder = struct {
163161 }
164162};
165163
166error OutputTooSmall;
167
168164pub const Base64DecoderWithIgnore = struct {
169165 decoder: Base64Decoder,
170166 char_is_ignored: [256]bool,
......@@ -185,7 +181,7 @@ pub const Base64DecoderWithIgnore = struct {
185181 }
186182
187183 /// 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 {
189185 return @divTrunc(encoded_len, 4) * 3;
190186 }
191187
......@@ -193,7 +189,7 @@ pub const Base64DecoderWithIgnore = struct {
193189 /// Invalid padding results in error.InvalidPadding.
194190 /// Decoding more data than can fit in dest results in error.OutputTooSmall. See also ::calcSizeUpperBound.
195191 /// 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 {
197193 const decoder = &decoder_with_ignore.decoder;
198194
199195 var src_cursor: usize = 0;
......@@ -378,7 +374,7 @@ test "base64" {
378374 comptime (testBase64() catch unreachable);
379375}
380376
381fn testBase64() %void {
377fn testBase64() !void {
382378 try testAllApis("", "");
383379 try testAllApis("f", "Zg==");
384380 try testAllApis("fo", "Zm8=");
......@@ -412,7 +408,7 @@ fn testBase64() %void {
412408 try testOutputTooSmallError("AAAAAA==");
413409}
414410
415fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) %void {
411fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void {
416412 // Base64Encoder
417413 {
418414 var buffer: [0x100]u8 = undefined;
......@@ -434,7 +430,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) %void
434430 const standard_decoder_ignore_nothing = Base64DecoderWithIgnore.init(
435431 standard_alphabet_chars, standard_pad_char, "");
436432 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)];
438434 var written = try standard_decoder_ignore_nothing.decode(decoded, expected_encoded);
439435 assert(written <= decoded.len);
440436 assert(mem.eql(u8, decoded[0..written], expected_decoded));
......@@ -449,17 +445,16 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) %void
449445 }
450446}
451447
452fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) %void {
448fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) !void {
453449 const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
454450 standard_alphabet_chars, standard_pad_char, " ");
455451 var buffer: [0x100]u8 = undefined;
456 var decoded = buffer[0..try Base64DecoderWithIgnore.calcSizeUpperBound(encoded.len)];
452 var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(encoded.len)];
457453 var written = try standard_decoder_ignore_space.decode(decoded, encoded);
458454 assert(mem.eql(u8, decoded[0..written], expected_decoded));
459455}
460456
461error ExpectedError;
462fn testError(encoded: []const u8, expected_err: error) %void {
457fn testError(encoded: []const u8, expected_err: error) !void {
463458 const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
464459 standard_alphabet_chars, standard_pad_char, " ");
465460 var buffer: [0x100]u8 = undefined;
......@@ -475,7 +470,7 @@ fn testError(encoded: []const u8, expected_err: error) %void {
475470 } else |err| if (err != expected_err) return err;
476471}
477472
478fn testOutputTooSmallError(encoded: []const u8) %void {
473fn testOutputTooSmallError(encoded: []const u8) !void {
479474 const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
480475 standard_alphabet_chars, standard_pad_char, " ");
481476 var buffer: [0x100]u8 = undefined;
std/buf_map.zig+2-2
......@@ -27,7 +27,7 @@ pub const BufMap = struct {
2727 self.hash_map.deinit();
2828 }
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 {
3131 if (self.hash_map.get(key)) |entry| {
3232 const value_copy = try self.copy(value);
3333 errdefer self.free(value_copy);
......@@ -67,7 +67,7 @@ pub const BufMap = struct {
6767 self.hash_map.allocator.free(mut_value);
6868 }
6969
70 fn copy(self: &BufMap, value: []const u8) %[]const u8 {
70 fn copy(self: &BufMap, value: []const u8) ![]const u8 {
7171 const result = try self.hash_map.allocator.alloc(u8, value.len);
7272 mem.copy(u8, result, value);
7373 return result;
std/buf_set.zig+2-2
......@@ -24,7 +24,7 @@ pub const BufSet = struct {
2424 self.hash_map.deinit();
2525 }
2626
27 pub fn put(self: &BufSet, key: []const u8) %void {
27 pub fn put(self: &BufSet, key: []const u8) !void {
2828 if (self.hash_map.get(key) == null) {
2929 const key_copy = try self.copy(key);
3030 errdefer self.free(key_copy);
......@@ -55,7 +55,7 @@ pub const BufSet = struct {
5555 self.hash_map.allocator.free(mut_value);
5656 }
5757
58 fn copy(self: &BufSet, value: []const u8) %[]const u8 {
58 fn copy(self: &BufSet, value: []const u8) ![]const u8 {
5959 const result = try self.hash_map.allocator.alloc(u8, value.len);
6060 mem.copy(u8, result, value);
6161 return result;
std/buffer.zig+9-9
......@@ -12,14 +12,14 @@ pub const Buffer = struct {
1212 list: ArrayList(u8),
1313
1414 /// Must deinitialize with deinit.
15 pub fn init(allocator: &Allocator, m: []const u8) %Buffer {
15 pub fn init(allocator: &Allocator, m: []const u8) !Buffer {
1616 var self = try initSize(allocator, m.len);
1717 mem.copy(u8, self.list.items, m);
1818 return self;
1919 }
2020
2121 /// Must deinitialize with deinit.
22 pub fn initSize(allocator: &Allocator, size: usize) %Buffer {
22 pub fn initSize(allocator: &Allocator, size: usize) !Buffer {
2323 var self = initNull(allocator);
2424 try self.resize(size);
2525 return self;
......@@ -37,7 +37,7 @@ pub const Buffer = struct {
3737 }
3838
3939 /// Must deinitialize with deinit.
40 pub fn initFromBuffer(buffer: &const Buffer) %Buffer {
40 pub fn initFromBuffer(buffer: &const Buffer) !Buffer {
4141 return Buffer.init(buffer.list.allocator, buffer.toSliceConst());
4242 }
4343
......@@ -80,7 +80,7 @@ pub const Buffer = struct {
8080 self.list.items[self.len()] = 0;
8181 }
8282
83 pub fn resize(self: &Buffer, new_len: usize) %void {
83 pub fn resize(self: &Buffer, new_len: usize) !void {
8484 try self.list.resize(new_len + 1);
8585 self.list.items[self.len()] = 0;
8686 }
......@@ -93,24 +93,24 @@ pub const Buffer = struct {
9393 return self.list.len - 1;
9494 }
9595
96 pub fn append(self: &Buffer, m: []const u8) %void {
96 pub fn append(self: &Buffer, m: []const u8) !void {
9797 const old_len = self.len();
9898 try self.resize(old_len + m.len);
9999 mem.copy(u8, self.list.toSlice()[old_len..], m);
100100 }
101101
102102 // 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 {
104104 return fmt.format(self, append, format, args);
105105 }
106106
107107 // TODO: remove, use OutStream for this
108 pub fn appendByte(self: &Buffer, byte: u8) %void {
108 pub fn appendByte(self: &Buffer, byte: u8) !void {
109109 return self.appendByteNTimes(byte, 1);
110110 }
111111
112112 // 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 {
114114 var prev_size: usize = self.len();
115115 const new_size = prev_size + count;
116116 try self.resize(new_size);
......@@ -137,7 +137,7 @@ pub const Buffer = struct {
137137 return mem.eql(u8, self.list.items[start..l], m);
138138 }
139139
140 pub fn replaceContents(self: &const Buffer, m: []const u8) %void {
140 pub fn replaceContents(self: &const Buffer, m: []const u8) !void {
141141 try self.resize(m.len);
142142 mem.copy(u8, self.list.toSlice(), m);
143143 }
std/build.zig+26-33
......@@ -15,13 +15,6 @@ const BufSet = std.BufSet;
1515const BufMap = std.BufMap;
1616const fmt_lib = std.fmt;
1717
18error ExtraArg;
19error UncleanExit;
20error InvalidStepName;
21error DependencyLoopDetected;
22error NoCompilerFound;
23error NeedAnObject;
24
2518pub const Builder = struct {
2619 uninstall_tls: TopLevelStep,
2720 install_tls: TopLevelStep,
......@@ -242,7 +235,7 @@ pub const Builder = struct {
242235 self.lib_paths.append(path) catch unreachable;
243236 }
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 {
246239 var wanted_steps = ArrayList(&Step).init(self.allocator);
247240 defer wanted_steps.deinit();
248241
......@@ -278,7 +271,7 @@ pub const Builder = struct {
278271 return &self.uninstall_tls.step;
279272 }
280273
281 fn makeUninstall(uninstall_step: &Step) %void {
274 fn makeUninstall(uninstall_step: &Step) error!void {
282275 const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step);
283276 const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls);
284277
......@@ -292,7 +285,7 @@ pub const Builder = struct {
292285 // TODO remove empty directories
293286 }
294287
295 fn makeOneStep(self: &Builder, s: &Step) %void {
288 fn makeOneStep(self: &Builder, s: &Step) error!void {
296289 if (s.loop_flag) {
297290 warn("Dependency loop detected:\n {}\n", s.name);
298291 return error.DependencyLoopDetected;
......@@ -313,7 +306,7 @@ pub const Builder = struct {
313306 try s.make();
314307 }
315308
316 fn getTopLevelStepByName(self: &Builder, name: []const u8) %&Step {
309 fn getTopLevelStepByName(self: &Builder, name: []const u8) !&Step {
317310 for (self.top_level_steps.toSliceConst()) |top_level_step| {
318311 if (mem.eql(u8, top_level_step.step.name, name)) {
319312 return &top_level_step.step;
......@@ -548,7 +541,7 @@ pub const Builder = struct {
548541 return self.invalid_user_input;
549542 }
550543
551 fn spawnChild(self: &Builder, argv: []const []const u8) %void {
544 fn spawnChild(self: &Builder, argv: []const []const u8) !void {
552545 return self.spawnChildEnvMap(null, &self.env_map, argv);
553546 }
554547
......@@ -561,7 +554,7 @@ pub const Builder = struct {
561554 }
562555
563556 fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
564 argv: []const []const u8) %void
557 argv: []const []const u8) !void
565558 {
566559 if (self.verbose) {
567560 printCmd(cwd, argv);
......@@ -595,7 +588,7 @@ pub const Builder = struct {
595588 }
596589 }
597590
598 pub fn makePath(self: &Builder, path: []const u8) %void {
591 pub fn makePath(self: &Builder, path: []const u8) !void {
599592 os.makePath(self.allocator, self.pathFromRoot(path)) catch |err| {
600593 warn("Unable to create path {}: {}\n", path, @errorName(err));
601594 return err;
......@@ -630,11 +623,11 @@ pub const Builder = struct {
630623 self.installed_files.append(full_path) catch unreachable;
631624 }
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 {
634627 return self.copyFileMode(source_path, dest_path, 0o666);
635628 }
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 {
638631 if (self.verbose) {
639632 warn("cp {} {}\n", source_path, dest_path);
640633 }
......@@ -672,7 +665,7 @@ pub const Builder = struct {
672665 }
673666 }
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 {
676669 // TODO report error for ambiguous situations
677670 const exe_extension = (Target { .Native = {}}).exeFileExt();
678671 for (self.search_prefixes.toSliceConst()) |search_prefix| {
......@@ -721,7 +714,7 @@ pub const Builder = struct {
721714 return error.FileNotFound;
722715 }
723716
724 pub fn exec(self: &Builder, argv: []const []const u8) %[]u8 {
717 pub fn exec(self: &Builder, argv: []const []const u8) ![]u8 {
725718 const max_output_size = 100 * 1024;
726719 const result = try os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size);
727720 switch (result.term) {
......@@ -1180,12 +1173,12 @@ pub const LibExeObjStep = struct {
11801173 self.disable_libc = disable;
11811174 }
11821175
1183 fn make(step: &Step) %void {
1176 fn make(step: &Step) !void {
11841177 const self = @fieldParentPtr(LibExeObjStep, "step", step);
11851178 return if (self.is_zig) self.makeZig() else self.makeC();
11861179 }
11871180
1188 fn makeZig(self: &LibExeObjStep) %void {
1181 fn makeZig(self: &LibExeObjStep) !void {
11891182 const builder = self.builder;
11901183
11911184 assert(self.is_zig);
......@@ -1396,7 +1389,7 @@ pub const LibExeObjStep = struct {
13961389 }
13971390 }
13981391
1399 fn makeC(self: &LibExeObjStep) %void {
1392 fn makeC(self: &LibExeObjStep) !void {
14001393 const builder = self.builder;
14011394
14021395 const cc = builder.getCCExe();
......@@ -1687,7 +1680,7 @@ pub const TestStep = struct {
16871680 self.exec_cmd_args = args;
16881681 }
16891682
1690 fn make(step: &Step) %void {
1683 fn make(step: &Step) !void {
16911684 const self = @fieldParentPtr(TestStep, "step", step);
16921685 const builder = self.builder;
16931686
......@@ -1796,7 +1789,7 @@ pub const CommandStep = struct {
17961789 return self;
17971790 }
17981791
1799 fn make(step: &Step) %void {
1792 fn make(step: &Step) !void {
18001793 const self = @fieldParentPtr(CommandStep, "step", step);
18011794
18021795 const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else self.builder.build_root;
......@@ -1836,7 +1829,7 @@ const InstallArtifactStep = struct {
18361829 return self;
18371830 }
18381831
1839 fn make(step: &Step) %void {
1832 fn make(step: &Step) !void {
18401833 const self = @fieldParentPtr(Self, "step", step);
18411834 const builder = self.builder;
18421835
......@@ -1868,7 +1861,7 @@ pub const InstallFileStep = struct {
18681861 };
18691862 }
18701863
1871 fn make(step: &Step) %void {
1864 fn make(step: &Step) !void {
18721865 const self = @fieldParentPtr(InstallFileStep, "step", step);
18731866 try self.builder.copyFile(self.src_path, self.dest_path);
18741867 }
......@@ -1889,7 +1882,7 @@ pub const WriteFileStep = struct {
18891882 };
18901883 }
18911884
1892 fn make(step: &Step) %void {
1885 fn make(step: &Step) !void {
18931886 const self = @fieldParentPtr(WriteFileStep, "step", step);
18941887 const full_path = self.builder.pathFromRoot(self.file_path);
18951888 const full_path_dir = os.path.dirname(full_path);
......@@ -1917,7 +1910,7 @@ pub const LogStep = struct {
19171910 };
19181911 }
19191912
1920 fn make(step: &Step) %void {
1913 fn make(step: &Step) error!void {
19211914 const self = @fieldParentPtr(LogStep, "step", step);
19221915 warn("{}", self.data);
19231916 }
......@@ -1936,7 +1929,7 @@ pub const RemoveDirStep = struct {
19361929 };
19371930 }
19381931
1939 fn make(step: &Step) %void {
1932 fn make(step: &Step) !void {
19401933 const self = @fieldParentPtr(RemoveDirStep, "step", step);
19411934
19421935 const full_path = self.builder.pathFromRoot(self.dir_path);
......@@ -1949,12 +1942,12 @@ pub const RemoveDirStep = struct {
19491942
19501943pub const Step = struct {
19511944 name: []const u8,
1952 makeFn: fn(self: &Step) %void,
1945 makeFn: fn(self: &Step) error!void,
19531946 dependencies: ArrayList(&Step),
19541947 loop_flag: bool,
19551948 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 {
19581951 return Step {
19591952 .name = name,
19601953 .makeFn = makeFn,
......@@ -1967,7 +1960,7 @@ pub const Step = struct {
19671960 return init(name, allocator, makeNoOp);
19681961 }
19691962
1970 pub fn make(self: &Step) %void {
1963 pub fn make(self: &Step) !void {
19711964 if (self.done_flag)
19721965 return;
19731966
......@@ -1979,11 +1972,11 @@ pub const Step = struct {
19791972 self.dependencies.append(other) catch unreachable;
19801973 }
19811974
1982 fn makeNoOp(self: &Step) %void {}
1975 fn makeNoOp(self: &Step) error!void {}
19831976};
19841977
19851978fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_major_only: []const u8,
1986 filename_name_only: []const u8) %void
1979 filename_name_only: []const u8) !void
19871980{
19881981 const out_dir = os.path.dirname(output_path);
19891982 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;
2020pub extern "c" fn raise(sig: c_int) c_int;
2121pub extern "c" fn read(fd: c_int, buf: &c_void, nbyte: usize) isize;
2222pub 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;
2424pub extern "c" fn mmap(addr: ?&c_void, len: usize, prot: c_int, flags: c_int,
2525 fd: c_int, offset: isize) ?&c_void;
2626pub 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({
1818
1919const Mb = 1024 * 1024;
2020
21pub fn main() %void {
21pub fn main() !void {
2222 var stdout_file = try std.io.getStdOut();
2323 var stdout_out_stream = std.io.FileOutStream.init(&stdout_file);
2424 const stdout = &stdout_out_stream.stream;
std/cstr.zig+2-2
......@@ -42,7 +42,7 @@ fn testCStrFnsImpl() void {
4242/// Returns a mutable slice with exactly the same size which is guaranteed to
4343/// have a null byte after it.
4444/// 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 {
4646 const result = try allocator.alloc(u8, slice.len + 1);
4747 mem.copy(u8, result, slice);
4848 result[slice.len] = 0;
......@@ -56,7 +56,7 @@ pub const NullTerminated2DArray = struct {
5656
5757 /// Takes N lists of strings, concatenates the lists together, and adds a null terminator
5858 /// 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 {
6060 var new_len: usize = 1; // 1 for the list null
6161 var byte_count: usize = 0;
6262 for (slices) |slice| {
std/debug/failing_allocator.zig+2-2
......@@ -28,7 +28,7 @@ pub const FailingAllocator = struct {
2828 };
2929 }
3030
31 fn alloc(allocator: &mem.Allocator, n: usize, alignment: u29) %[]u8 {
31 fn alloc(allocator: &mem.Allocator, n: usize, alignment: u29) ![]u8 {
3232 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
3333 if (self.index == self.fail_index) {
3434 return error.OutOfMemory;
......@@ -39,7 +39,7 @@ pub const FailingAllocator = struct {
3939 return result;
4040 }
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 {
4343 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
4444 if (new_size <= old_mem.len) {
4545 self.freed_bytes += old_mem.len - new_size;
std/debug/index.zig+52-52
......@@ -10,26 +10,17 @@ const builtin = @import("builtin");
1010
1111pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;
1212
13error MissingDebugInfo;
14error InvalidDebugInfo;
15error UnsupportedDebugInfo;
16error UnknownObjectFormat;
17error TodoSupportCoffDebugInfo;
18error TodoSupportMachoDebugInfo;
19error TodoSupportCOFFDebugInfo;
20
21
2213/// Tries to write to stderr, unbuffered, and ignores any error returned.
2314/// Does not append a newline.
2415/// TODO atomic/multithread support
2516var stderr_file: io.File = undefined;
2617var stderr_file_out_stream: io.FileOutStream = undefined;
27var stderr_stream: ?&io.OutStream = null;
18var stderr_stream: ?&io.OutStream(io.FileOutStream.Error) = null;
2819pub fn warn(comptime fmt: []const u8, args: ...) void {
2920 const stderr = getStderrStream() catch return;
3021 stderr.print(fmt, args) catch return;
3122}
32fn getStderrStream() %&io.OutStream {
23fn getStderrStream() !&io.OutStream(io.FileOutStream.Error) {
3324 if (stderr_stream) |st| {
3425 return st;
3526 } else {
......@@ -42,7 +33,7 @@ fn getStderrStream() %&io.OutStream {
4233}
4334
4435var self_debug_info: ?&ElfStackTrace = null;
45pub fn getSelfDebugInfo() %&ElfStackTrace {
36pub fn getSelfDebugInfo() !&ElfStackTrace {
4637 if (self_debug_info) |info| {
4738 return info;
4839 } else {
......@@ -149,11 +140,8 @@ const WHITE = "\x1b[37;1m";
149140const DIM = "\x1b[2m";
150141const RESET = "\x1b[0m";
151142
152error PathNotFound;
153error InvalidDebugInfo;
154
155pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator,
156 debug_info: &ElfStackTrace, tty_color: bool) %void
143pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var, allocator: &mem.Allocator,
144 debug_info: &ElfStackTrace, tty_color: bool) !void
157145{
158146 var frame_index: usize = undefined;
159147 var frames_left: usize = undefined;
......@@ -174,8 +162,8 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.O
174162 }
175163}
176164
177pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator,
178 debug_info: &ElfStackTrace, tty_color: bool, ignore_frame_count: usize) %void
165pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,
166 debug_info: &ElfStackTrace, tty_color: bool, ignore_frame_count: usize) !void
179167{
180168 var ignored_count: usize = 0;
181169
......@@ -191,7 +179,7 @@ pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocat
191179 }
192180}
193181
194fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, address: usize) %void {
182fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: var, address: usize) !void {
195183 if (builtin.os == builtin.Os.windows) {
196184 return error.UnsupportedDebugInfo;
197185 }
......@@ -221,7 +209,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a
221209 try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
222210 }
223211 } else |err| switch (err) {
224 error.EndOfFile, error.PathNotFound => {},
212 error.EndOfFile => {},
225213 else => return err,
226214 }
227215 } else |err| switch (err) {
......@@ -232,7 +220,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a
232220 }
233221}
234222
235pub fn openSelfDebugInfo(allocator: &mem.Allocator) %&ElfStackTrace {
223pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {
236224 switch (builtin.object_format) {
237225 builtin.ObjectFormat.elf => {
238226 const st = try allocator.create(ElfStackTrace);
......@@ -276,7 +264,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) %&ElfStackTrace {
276264 }
277265}
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 {
280268 var f = try io.File.openRead(line_info.file_name, allocator);
281269 defer f.close();
282270 // TODO fstat and make sure that the file has the correct size
......@@ -324,7 +312,7 @@ pub const ElfStackTrace = struct {
324312 return self.abbrev_table_list.allocator;
325313 }
326314
327 pub fn readString(self: &ElfStackTrace) %[]u8 {
315 pub fn readString(self: &ElfStackTrace) ![]u8 {
328316 var in_file_stream = io.FileInStream.init(&self.self_exe_file);
329317 const in_stream = &in_file_stream.stream;
330318 return readStringRaw(self.allocator(), in_stream);
......@@ -387,7 +375,7 @@ const Constant = struct {
387375 payload: []u8,
388376 signed: bool,
389377
390 fn asUnsignedLe(self: &const Constant) %u64 {
378 fn asUnsignedLe(self: &const Constant) !u64 {
391379 if (self.payload.len > @sizeOf(u64))
392380 return error.InvalidDebugInfo;
393381 if (self.signed)
......@@ -414,7 +402,7 @@ const Die = struct {
414402 return null;
415403 }
416404
417 fn getAttrAddr(self: &const Die, id: u64) %u64 {
405 fn getAttrAddr(self: &const Die, id: u64) !u64 {
418406 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
419407 return switch (*form_value) {
420408 FormValue.Address => |value| value,
......@@ -422,7 +410,7 @@ const Die = struct {
422410 };
423411 }
424412
425 fn getAttrSecOffset(self: &const Die, id: u64) %u64 {
413 fn getAttrSecOffset(self: &const Die, id: u64) !u64 {
426414 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
427415 return switch (*form_value) {
428416 FormValue.Const => |value| value.asUnsignedLe(),
......@@ -431,7 +419,7 @@ const Die = struct {
431419 };
432420 }
433421
434 fn getAttrUnsignedLe(self: &const Die, id: u64) %u64 {
422 fn getAttrUnsignedLe(self: &const Die, id: u64) !u64 {
435423 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
436424 return switch (*form_value) {
437425 FormValue.Const => |value| value.asUnsignedLe(),
......@@ -439,7 +427,7 @@ const Die = struct {
439427 };
440428 }
441429
442 fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) %[]u8 {
430 fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) ![]u8 {
443431 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
444432 return switch (*form_value) {
445433 FormValue.String => |value| value,
......@@ -512,7 +500,7 @@ const LineNumberProgram = struct {
512500 };
513501 }
514502
515 pub fn checkLineMatch(self: &LineNumberProgram) %?LineInfo {
503 pub fn checkLineMatch(self: &LineNumberProgram) !?LineInfo {
516504 if (self.target_address >= self.prev_address and self.target_address < self.address) {
517505 const file_entry = if (self.prev_file == 0) {
518506 return error.MissingDebugInfo;
......@@ -544,7 +532,7 @@ const LineNumberProgram = struct {
544532 }
545533};
546534
547fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) %[]u8 {
535fn readStringRaw(allocator: &mem.Allocator, in_stream: var) ![]u8 {
548536 var buf = ArrayList(u8).init(allocator);
549537 while (true) {
550538 const byte = try in_stream.readByte();
......@@ -555,58 +543,70 @@ fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) %[]u8 {
555543 return buf.toSlice();
556544}
557545
558fn getString(st: &ElfStackTrace, offset: u64) %[]u8 {
546fn getString(st: &ElfStackTrace, offset: u64) ![]u8 {
559547 const pos = st.debug_str.offset + offset;
560548 try st.self_exe_file.seekTo(pos);
561549 return st.readString();
562550}
563551
564fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) %[]u8 {
552fn readAllocBytes(allocator: &mem.Allocator, in_stream: var, size: usize) ![]u8 {
565553 const buf = try global_allocator.alloc(u8, size);
566554 errdefer global_allocator.free(buf);
567555 if ((try in_stream.read(buf)) < size) return error.EndOfFile;
568556 return buf;
569557}
570558
571fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) %FormValue {
559fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
572560 const buf = try readAllocBytes(allocator, in_stream, size);
573561 return FormValue { .Block = buf };
574562}
575563
576fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) %FormValue {
564fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
577565 const block_len = try in_stream.readVarInt(builtin.Endian.Little, usize, size);
578566 return parseFormValueBlockLen(allocator, in_stream, block_len);
579567}
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 {
582570 return FormValue { .Const = Constant {
583571 .signed = signed,
584572 .payload = try readAllocBytes(allocator, in_stream, size),
585573 }};
586574}
587575
588fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) %u64 {
576fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
589577 return if (is_64) try in_stream.readIntLe(u64)
590578 else u64(try in_stream.readIntLe(u32)) ;
591579}
592580
593fn parseFormValueTargetAddrSize(in_stream: &io.InStream) %u64 {
581fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
594582 return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32))
595583 else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64)
596584 else unreachable;
597585}
598586
599fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) %FormValue {
587fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
600588 const buf = try readAllocBytes(allocator, in_stream, size);
601589 return FormValue { .Ref = buf };
602590}
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 {
605593 const block_len = try in_stream.readIntLe(T);
606594 return parseFormValueRefLen(allocator, in_stream, block_len);
607595}
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{
610610 return switch (form_id) {
611611 DW.FORM_addr => FormValue { .Address = try parseFormValueTargetAddrSize(in_stream) },
612612 DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
......@@ -656,7 +656,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
656656 };
657657}
658658
659fn parseAbbrevTable(st: &ElfStackTrace) %AbbrevTable {
659fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable {
660660 const in_file = &st.self_exe_file;
661661 var in_file_stream = io.FileInStream.init(in_file);
662662 const in_stream = &in_file_stream.stream;
......@@ -688,7 +688,7 @@ fn parseAbbrevTable(st: &ElfStackTrace) %AbbrevTable {
688688
689689/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
690690/// 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 {
692692 for (st.abbrev_table_list.toSlice()) |*header| {
693693 if (header.offset == abbrev_offset) {
694694 return &header.table;
......@@ -710,7 +710,7 @@ fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) ?&con
710710 return null;
711711}
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 {
714714 const in_file = &st.self_exe_file;
715715 var in_file_stream = io.FileInStream.init(in_file);
716716 const in_stream = &in_file_stream.stream;
......@@ -732,7 +732,7 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) %
732732 return result;
733733}
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 {
736736 const compile_unit_cwd = try compile_unit.die.getAttrString(st, DW.AT_comp_dir);
737737
738738 const in_file = &st.self_exe_file;
......@@ -747,7 +747,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
747747 try in_file.seekTo(this_offset);
748748
749749 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);
751751 if (unit_length == 0)
752752 return error.MissingDebugInfo;
753753 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
910910 return error.MissingDebugInfo;
911911}
912912
913fn scanAllCompileUnits(st: &ElfStackTrace) %void {
913fn scanAllCompileUnits(st: &ElfStackTrace) !void {
914914 const debug_info_end = st.debug_info.offset + st.debug_info.size;
915915 var this_unit_offset = st.debug_info.offset;
916916 var cu_index: usize = 0;
......@@ -922,7 +922,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) %void {
922922 try st.self_exe_file.seekTo(this_unit_offset);
923923
924924 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);
926926 if (unit_length == 0)
927927 return;
928928 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
......@@ -986,7 +986,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) %void {
986986 }
987987}
988988
989fn findCompileUnit(st: &ElfStackTrace, target_address: u64) %&const CompileUnit {
989fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit {
990990 var in_file_stream = io.FileInStream.init(&st.self_exe_file);
991991 const in_stream = &in_file_stream.stream;
992992 for (st.compile_unit_list.toSlice()) |*compile_unit| {
......@@ -1022,7 +1022,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) %&const CompileUnit
10221022 return error.MissingDebugInfo;
10231023}
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 {
10261026 const first_32_bits = try in_stream.readIntLe(u32);
10271027 *is_64 = (first_32_bits == 0xffffffff);
10281028 if (*is_64) {
......@@ -1033,7 +1033,7 @@ fn readInitialLength(in_stream: &io.InStream, is_64: &bool) %u64 {
10331033 }
10341034}
10351035
1036fn readULeb128(in_stream: &io.InStream) %u64 {
1036fn readULeb128(in_stream: var) !u64 {
10371037 var result: u64 = 0;
10381038 var shift: usize = 0;
10391039
......@@ -1054,7 +1054,7 @@ fn readULeb128(in_stream: &io.InStream) %u64 {
10541054 }
10551055}
10561056
1057fn readILeb128(in_stream: &io.InStream) %i64 {
1057fn readILeb128(in_stream: var) !i64 {
10581058 var result: i64 = 0;
10591059 var shift: usize = 0;
10601060
std/elf.zig+4-6
......@@ -6,8 +6,6 @@ const mem = std.mem;
66const debug = std.debug;
77const InStream = std.stream.InStream;
88
9error InvalidFormat;
10
119pub const SHT_NULL = 0;
1210pub const SHT_PROGBITS = 1;
1311pub const SHT_SYMTAB = 2;
......@@ -81,14 +79,14 @@ pub const Elf = struct {
8179 prealloc_file: io.File,
8280
8381 /// 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 {
8583 try elf.prealloc_file.open(path);
8684 try elf.openFile(allocator, &elf.prealloc_file);
8785 elf.auto_close_stream = true;
8886 }
8987
9088 /// 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 {
9290 elf.allocator = allocator;
9391 elf.in_file = file;
9492 elf.auto_close_stream = false;
......@@ -239,7 +237,7 @@ pub const Elf = struct {
239237 elf.in_file.close();
240238 }
241239
242 pub fn findSection(elf: &Elf, name: []const u8) %?&SectionHeader {
240 pub fn findSection(elf: &Elf, name: []const u8) !?&SectionHeader {
243241 var file_stream = io.FileInStream.init(elf.in_file);
244242 const in = &file_stream.stream;
245243
......@@ -263,7 +261,7 @@ pub const Elf = struct {
263261 return null;
264262 }
265263
266 pub fn seekToSection(elf: &Elf, elf_section: &SectionHeader) %void {
264 pub fn seekToSection(elf: &Elf, elf_section: &SectionHeader) !void {
267265 try elf.in_file.seekTo(elf_section.offset);
268266 }
269267};
std/fmt/index.zig+56-52
......@@ -24,8 +24,8 @@ const State = enum { // TODO put inside format function and make sure the name a
2424/// Renders fmt string with args, calling output with slices of bytes.
2525/// If `output` returns an error, the error is returned from `format` and
2626/// `output` is not called again.
27pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
28 comptime fmt: []const u8, args: ...) %void
27pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void,
28 comptime fmt: []const u8, args: ...) Errors!void
2929{
3030 comptime var start_index = 0;
3131 comptime var state = State.Start;
......@@ -58,7 +58,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
5858 start_index = i;
5959 },
6060 '}' => {
61 try formatValue(args[next_arg], context, output);
61 try formatValue(args[next_arg], context, Errors, output);
6262 next_arg += 1;
6363 state = State.Start;
6464 start_index = i + 1;
......@@ -110,7 +110,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
110110 },
111111 State.Integer => switch (c) {
112112 '}' => {
113 try formatInt(args[next_arg], radix, uppercase, width, context, output);
113 try formatInt(args[next_arg], radix, uppercase, width, context, Errors, output);
114114 next_arg += 1;
115115 state = State.Start;
116116 start_index = i + 1;
......@@ -124,7 +124,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
124124 State.IntegerWidth => switch (c) {
125125 '}' => {
126126 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);
128128 next_arg += 1;
129129 state = State.Start;
130130 start_index = i + 1;
......@@ -134,7 +134,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
134134 },
135135 State.Float => switch (c) {
136136 '}' => {
137 try formatFloatDecimal(args[next_arg], 0, context, output);
137 try formatFloatDecimal(args[next_arg], 0, context, Errors, output);
138138 next_arg += 1;
139139 state = State.Start;
140140 start_index = i + 1;
......@@ -148,7 +148,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
148148 State.FloatWidth => switch (c) {
149149 '}' => {
150150 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);
152152 next_arg += 1;
153153 state = State.Start;
154154 start_index = i + 1;
......@@ -159,7 +159,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
159159 State.BufWidth => switch (c) {
160160 '}' => {
161161 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);
163163 next_arg += 1;
164164 state = State.Start;
165165 start_index = i + 1;
......@@ -169,7 +169,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
169169 },
170170 State.Character => switch (c) {
171171 '}' => {
172 try formatAsciiChar(args[next_arg], context, output);
172 try formatAsciiChar(args[next_arg], context, Errors, output);
173173 next_arg += 1;
174174 state = State.Start;
175175 start_index = i + 1;
......@@ -191,14 +191,14 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void,
191191 }
192192}
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 {
195195 const T = @typeOf(value);
196196 switch (@typeId(T)) {
197197 builtin.TypeId.Int => {
198 return formatInt(value, 10, false, 0, context, output);
198 return formatInt(value, 10, false, 0, context, Errors, output);
199199 },
200200 builtin.TypeId.Float => {
201 return formatFloat(value, context, output);
201 return formatFloat(value, context, Errors, output);
202202 },
203203 builtin.TypeId.Void => {
204204 return output(context, "void");
......@@ -208,19 +208,19 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons
208208 },
209209 builtin.TypeId.Nullable => {
210210 if (value) |payload| {
211 return formatValue(payload, context, output);
211 return formatValue(payload, context, Errors, output);
212212 } else {
213213 return output(context, "null");
214214 }
215215 },
216216 builtin.TypeId.ErrorUnion => {
217217 if (value) |payload| {
218 return formatValue(payload, context, output);
218 return formatValue(payload, context, Errors, output);
219219 } else |err| {
220 return formatValue(err, context, output);
220 return formatValue(err, context, Errors, output);
221221 }
222222 },
223 builtin.TypeId.Error => {
223 builtin.TypeId.ErrorSet => {
224224 try output(context, "error.");
225225 return output(context, @errorName(value));
226226 },
......@@ -228,7 +228,7 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons
228228 if (@typeId(T.Child) == builtin.TypeId.Array and T.Child.Child == u8) {
229229 return output(context, (*value)[0..]);
230230 } else {
231 return format(context, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
231 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
232232 }
233233 },
234234 else => if (@canImplicitCast([]const u8, value)) {
......@@ -240,12 +240,12 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons
240240 }
241241}
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 {
244244 return output(context, (&c)[0..1]);
245245}
246246
247247pub fn formatBuf(buf: []const u8, width: usize,
248 context: var, output: fn(@typeOf(context), []const u8)%void) %void
248 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
249249{
250250 try output(context, buf);
251251
......@@ -256,7 +256,7 @@ pub fn formatBuf(buf: []const u8, width: usize,
256256 }
257257}
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 {
260260 var x = f64(value);
261261
262262 // Errol doesn't handle these special cases.
......@@ -290,11 +290,11 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons
290290
291291 if (float_decimal.exp != 1) {
292292 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);
294294 }
295295}
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 {
298298 var x = f64(value);
299299
300300 // Errol doesn't handle these special cases.
......@@ -336,17 +336,17 @@ pub fn formatFloatDecimal(value: var, precision: usize, context: var, output: fn
336336
337337
338338pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,
339 context: var, output: fn(@typeOf(context), []const u8)%void) %void
339 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
340340{
341341 if (@typeOf(value).is_signed) {
342 return formatIntSigned(value, base, uppercase, width, context, output);
342 return formatIntSigned(value, base, uppercase, width, context, Errors, output);
343343 } else {
344 return formatIntUnsigned(value, base, uppercase, width, context, output);
344 return formatIntUnsigned(value, base, uppercase, width, context, Errors, output);
345345 }
346346}
347347
348348fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,
349 context: var, output: fn(@typeOf(context), []const u8)%void) %void
349 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
350350{
351351 const uint = @IntType(false, @typeOf(value).bit_count);
352352 if (value < 0) {
......@@ -354,20 +354,20 @@ fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,
354354 try output(context, (&minus_sign)[0..1]);
355355 const new_value = uint(-(value + 1)) + 1;
356356 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);
358358 } 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);
360360 } else {
361361 const plus_sign: u8 = '+';
362362 try output(context, (&plus_sign)[0..1]);
363363 const new_value = uint(value);
364364 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);
366366 }
367367}
368368
369369fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
370 context: var, output: fn(@typeOf(context), []const u8)%void) %void
370 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
371371{
372372 // max_int_digits accounts for the minus sign. when printing an unsigned
373373 // 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:
410410 .out_buf = out_buf,
411411 .index = 0,
412412 };
413 formatInt(value, base, uppercase, width, &context, formatIntCallback) catch unreachable;
413 formatInt(value, base, uppercase, width, &context, error{}, formatIntCallback) catch unreachable;
414414 return context.index;
415415}
416416const FormatIntBuf = struct {
417417 out_buf: []u8,
418418 index: usize,
419419};
420fn formatIntCallback(context: &FormatIntBuf, bytes: []const u8) %void {
420fn formatIntCallback(context: &FormatIntBuf, bytes: []const u8) (error{}!void) {
421421 mem.copy(u8, context.out_buf[context.index..], bytes);
422422 context.index += bytes.len;
423423}
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 {
426426 if (!T.is_signed)
427427 return parseUnsigned(T, buf, radix);
428428 if (buf.len == 0)
......@@ -439,14 +439,21 @@ pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) %T {
439439test "fmt.parseInt" {
440440 assert((parseInt(i32, "-10", 10) catch unreachable) == -10);
441441 assert((parseInt(i32, "+10", 10) catch unreachable) == 10);
442 assert(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidChar);
443 assert(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidChar);
444 assert(if (parseInt(u32, "-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.InvalidCharacter);
444 assert(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter);
445445 assert((parseInt(u8, "255", 10) catch unreachable) == 255);
446446 assert(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
447447}
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 {
450457 var x: T = 0;
451458
452459 for (buf) |c| {
......@@ -458,17 +465,16 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) %T {
458465 return x;
459466}
460467
461error InvalidChar;
462fn charToDigit(c: u8, radix: u8) %u8 {
468fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
463469 const value = switch (c) {
464470 '0' ... '9' => c - '0',
465471 'A' ... 'Z' => c - 'A' + 10,
466472 'a' ... 'z' => c - 'a' + 10,
467 else => return error.InvalidChar,
473 else => return error.InvalidCharacter,
468474 };
469475
470476 if (value >= radix)
471 return error.InvalidChar;
477 return error.InvalidCharacter;
472478
473479 return value;
474480}
......@@ -485,28 +491,26 @@ const BufPrintContext = struct {
485491 remaining: []u8,
486492};
487493
488error BufferTooSmall;
489fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) %void {
494fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) !void {
490495 if (context.remaining.len < bytes.len) return error.BufferTooSmall;
491496 mem.copy(u8, context.remaining, bytes);
492497 context.remaining = context.remaining[bytes.len..];
493498}
494499
495pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) %[]u8 {
500pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {
496501 var context = BufPrintContext { .remaining = buf, };
497 try format(&context, bufPrintWrite, fmt, args);
502 try format(&context, error{BufferTooSmall}, bufPrintWrite, fmt, args);
498503 return buf[0..buf.len - context.remaining.len];
499504}
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 {
502507 var size: usize = 0;
503 // Cannot fail because `countSize` cannot fail.
504 format(&size, countSize, fmt, args) catch unreachable;
508 format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
505509 const buf = try allocator.alloc(u8, size);
506510 return bufPrint(buf, fmt, args);
507511}
508512
509fn countSize(size: &usize, bytes: []const u8) %void {
513fn countSize(size: &usize, bytes: []const u8) (error{}!void) {
510514 *size += bytes.len;
511515}
512516
......@@ -534,7 +538,7 @@ fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, width: u
534538
535539test "parse u64 digit too big" {
536540 _ = parseUnsigned(u64, "123a", 10) catch |err| {
537 if (err == error.InvalidChar) return;
541 if (err == error.InvalidCharacter) return;
538542 unreachable;
539543 };
540544 unreachable;
......@@ -567,13 +571,13 @@ test "fmt.format" {
567571 }
568572 {
569573 var buf1: [32]u8 = undefined;
570 const value: %i32 = 1234;
574 const value: error!i32 = 1234;
571575 const result = try bufPrint(buf1[0..], "error union: {}\n", value);
572576 assert(mem.eql(u8, result, "error union: 1234\n"));
573577 }
574578 {
575579 var buf1: [32]u8 = undefined;
576 const value: %i32 = error.InvalidChar;
580 const value: error!i32 = error.InvalidChar;
577581 const result = try bufPrint(buf1[0..], "error union: {}\n", value);
578582 assert(mem.eql(u8, result, "error union: error.InvalidChar\n"));
579583 }
std/hash_map.zig+2-2
......@@ -80,7 +80,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
8080 }
8181
8282 /// 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 {
8484 if (hm.entries.len == 0) {
8585 try hm.initCapacity(16);
8686 }
......@@ -151,7 +151,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
151151 };
152152 }
153153
154 fn initCapacity(hm: &Self, capacity: usize) %void {
154 fn initCapacity(hm: &Self, capacity: usize) !void {
155155 hm.entries = try hm.allocator.alloc(Entry, capacity);
156156 hm.size = 0;
157157 hm.max_distance_from_start_index = 0;
std/heap.zig+5-7
......@@ -9,8 +9,6 @@ const c = std.c;
99
1010const Allocator = mem.Allocator;
1111
12error OutOfMemory;
13
1412pub const c_allocator = &c_allocator_state;
1513var c_allocator_state = Allocator {
1614 .allocFn = cAlloc,
......@@ -18,14 +16,14 @@ var c_allocator_state = Allocator {
1816 .freeFn = cFree,
1917};
2018
21fn cAlloc(self: &Allocator, n: usize, alignment: u29) %[]u8 {
19fn cAlloc(self: &Allocator, n: usize, alignment: u29) ![]u8 {
2220 return if (c.malloc(usize(n))) |buf|
2321 @ptrCast(&u8, buf)[0..n]
2422 else
2523 error.OutOfMemory;
2624}
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 {
2927 const old_ptr = @ptrCast(&c_void, old_mem.ptr);
3028 if (c.realloc(old_ptr, new_size)) |buf| {
3129 return @ptrCast(&u8, buf)[0..new_size];
......@@ -47,7 +45,7 @@ pub const IncrementingAllocator = struct {
4745 end_index: usize,
4846 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 {
5149 switch (builtin.os) {
5250 Os.linux, Os.macosx, Os.ios => {
5351 const p = os.posix;
......@@ -105,7 +103,7 @@ pub const IncrementingAllocator = struct {
105103 return self.bytes.len - self.end_index;
106104 }
107105
108 fn alloc(allocator: &Allocator, n: usize, alignment: u29) %[]u8 {
106 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
109107 const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);
110108 const addr = @ptrToInt(&self.bytes[self.end_index]);
111109 const rem = @rem(addr, alignment);
......@@ -120,7 +118,7 @@ pub const IncrementingAllocator = struct {
120118 return result;
121119 }
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 {
124122 if (new_size <= old_mem.len) {
125123 return old_mem[0..new_size];
126124 } else {
std/io.zig+195-193
......@@ -26,31 +26,9 @@ test "import io tests" {
2626 }
2727}
2828
29/// The function received invalid input at runtime. An Invalid error means a
30/// bug in the program that called the function.
31error Invalid;
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 {
29const GetStdIoErrs = os.WindowsGetStdHandleErrs;
30
31pub fn getStdErr() GetStdIoErrs!File {
5432 const handle = if (is_windows)
5533 try os.windowsGetStdHandle(system.STD_ERROR_HANDLE)
5634 else if (is_posix)
......@@ -60,7 +38,7 @@ pub fn getStdErr() %File {
6038 return File.openHandle(handle);
6139}
6240
63pub fn getStdOut() %File {
41pub fn getStdOut() GetStdIoErrs!File {
6442 const handle = if (is_windows)
6543 try os.windowsGetStdHandle(system.STD_OUTPUT_HANDLE)
6644 else if (is_posix)
......@@ -70,7 +48,7 @@ pub fn getStdOut() %File {
7048 return File.openHandle(handle);
7149}
7250
73pub fn getStdIn() %File {
51pub fn getStdIn() GetStdIoErrs!File {
7452 const handle = if (is_windows)
7553 try os.windowsGetStdHandle(system.STD_INPUT_HANDLE)
7654 else if (is_posix)
......@@ -83,18 +61,21 @@ pub fn getStdIn() %File {
8361/// Implementation of InStream trait for File
8462pub const FileInStream = struct {
8563 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
8869 pub fn init(file: &File) FileInStream {
8970 return FileInStream {
9071 .file = file,
91 .stream = InStream {
72 .stream = Stream {
9273 .readFn = readFn,
9374 },
9475 };
9576 }
9677
97 fn readFn(in_stream: &InStream, buffer: []u8) %usize {
78 fn readFn(in_stream: &Stream, buffer: []u8) Error!usize {
9879 const self = @fieldParentPtr(FileInStream, "stream", in_stream);
9980 return self.file.read(buffer);
10081 }
......@@ -103,18 +84,21 @@ pub const FileInStream = struct {
10384/// Implementation of OutStream trait for File
10485pub const FileOutStream = struct {
10586 file: &File,
106 stream: OutStream,
87 stream: Stream,
88
89 pub const Error = File.WriteError;
90 pub const Stream = OutStream(Error);
10791
10892 pub fn init(file: &File) FileOutStream {
10993 return FileOutStream {
11094 .file = file,
111 .stream = OutStream {
95 .stream = Stream {
11296 .writeFn = writeFn,
11397 },
11498 };
11599 }
116100
117 fn writeFn(out_stream: &OutStream, bytes: []const u8) %void {
101 fn writeFn(out_stream: &Stream, bytes: []const u8) !void {
118102 const self = @fieldParentPtr(FileOutStream, "stream", out_stream);
119103 return self.file.write(bytes);
120104 }
......@@ -124,12 +108,14 @@ pub const File = struct {
124108 /// The OS-specific file descriptor or file handle.
125109 handle: os.FileHandle,
126110
111 const OpenError = os.WindowsOpenError || os.PosixOpenError;
112
127113 /// `path` may need to be copied in memory to add a null terminating byte. In this case
128114 /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed
129115 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.
130116 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
131117 /// 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 {
133119 if (is_posix) {
134120 const flags = system.O_LARGEFILE|system.O_RDONLY;
135121 const fd = try os.posixOpen(path, flags, 0, allocator);
......@@ -144,7 +130,7 @@ pub const File = struct {
144130 }
145131
146132 /// 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 {
148134 return openWriteMode(path, 0o666, allocator);
149135
150136 }
......@@ -154,7 +140,7 @@ pub const File = struct {
154140 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.
155141 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
156142 /// 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 {
158144 if (is_posix) {
159145 const flags = system.O_LARGEFILE|system.O_WRONLY|system.O_CREAT|system.O_CLOEXEC|system.O_TRUNC;
160146 const fd = try os.posixOpen(path, flags, mode, allocator);
......@@ -189,7 +175,7 @@ pub const File = struct {
189175 return os.isTty(self.handle);
190176 }
191177
192 pub fn seekForward(self: &File, amount: isize) %void {
178 pub fn seekForward(self: &File, amount: isize) !void {
193179 switch (builtin.os) {
194180 Os.linux, Os.macosx, Os.ios => {
195181 const result = system.lseek(self.handle, amount, system.SEEK_CUR);
......@@ -218,7 +204,7 @@ pub const File = struct {
218204 }
219205 }
220206
221 pub fn seekTo(self: &File, pos: usize) %void {
207 pub fn seekTo(self: &File, pos: usize) !void {
222208 switch (builtin.os) {
223209 Os.linux, Os.macosx, Os.ios => {
224210 const ipos = try math.cast(isize, pos);
......@@ -249,7 +235,7 @@ pub const File = struct {
249235 }
250236 }
251237
252 pub fn getPos(self: &File) %usize {
238 pub fn getPos(self: &File) !usize {
253239 switch (builtin.os) {
254240 Os.linux, Os.macosx, Os.ios => {
255241 const result = system.lseek(self.handle, 0, system.SEEK_CUR);
......@@ -289,7 +275,7 @@ pub const File = struct {
289275 }
290276 }
291277
292 pub fn getEndPos(self: &File) %usize {
278 pub fn getEndPos(self: &File) !usize {
293279 if (is_posix) {
294280 var stat: system.Stat = undefined;
295281 const err = system.getErrno(system.fstat(self.handle, &stat));
......@@ -318,7 +304,9 @@ pub const File = struct {
318304 }
319305 }
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 {
322310 if (is_posix) {
323311 var index: usize = 0;
324312 while (index < buffer.len) {
......@@ -360,7 +348,9 @@ pub const File = struct {
360348 }
361349 }
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 {
364354 if (is_posix) {
365355 try os.posixWrite(self.handle, bytes);
366356 } else if (is_windows) {
......@@ -371,180 +361,183 @@ pub const File = struct {
371361 }
372362};
373363
374error StreamTooLong;
375error EndOfStream;
376
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 }
364pub fn InStream(comptime Error: type) type {
365 return struct {
366 const Self = this;
406367
407 /// Allocates enough memory to hold all the contents of the stream. If the allocated
408 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.
409 /// Caller owns returned memory.
410 /// If this function returns an error, the contents from the stream read so far are lost.
411 pub fn readAllAlloc(self: &InStream, allocator: &mem.Allocator, max_size: usize) %[]u8 {
412 var buf = Buffer.initNull(allocator);
413 defer buf.deinit();
368 /// Return the number of bytes read. If the number read is smaller than buf.len, it
369 /// means the stream reached the end. Reaching the end of a stream is not an error
370 /// condition.
371 readFn: fn(self: &Self, buffer: []u8) Error!usize,
414372
415 try self.readAllBuffer(&buf, max_size);
416 return buf.toOwnedSlice();
417 }
373 /// Replaces `buffer` contents by reading from the stream until it is finished.
374 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and
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.
420 /// Does not include the delimiter in the result.
421 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents
422 /// read from the stream so far are lost.
423 pub fn readUntilDelimiterBuffer(self: &InStream, buffer: &Buffer, delimiter: u8, max_size: usize) %void {
424 try buf.resize(0);
379 var actual_buf_len: usize = 0;
380 while (true) {
381 const dest_slice = buffer.toSlice()[actual_buf_len..];
382 const bytes_read = try self.readFn(self, dest_slice);
383 actual_buf_len += bytes_read;
425384
426 while (true) {
427 var byte: u8 = try self.readByte();
385 if (bytes_read != dest_slice.len) {
386 buffer.shrink(actual_buf_len);
387 return;
388 }
428389
429 if (byte == delimiter) {
430 return;
390 const new_buf_size = math.min(max_size, actual_buf_len + os.page_size);
391 if (new_buf_size == actual_buf_len)
392 return error.StreamTooLong;
393 try buffer.resize(new_buf_size);
431394 }
395 }
432396
433 if (buf.len() == max_size) {
434 return error.StreamTooLong;
435 }
397 /// Allocates enough memory to hold all the contents of the stream. If the allocated
398 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.
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();
438407 }
439 }
440408
441 /// Allocates enough memory to read until `delimiter`. If the allocated
442 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.
443 /// Caller owns returned memory.
444 /// If this function returns an error, the contents from the stream read so far are lost.
445 pub fn readUntilDelimiterAlloc(self: &InStream, allocator: &mem.Allocator,
446 delimiter: u8, max_size: usize) %[]u8
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 }
409 /// Replaces `buffer` contents by reading from the stream until `delimiter` is found.
410 /// Does not include the delimiter in the result.
411 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents
412 /// read from the stream so far are lost.
413 pub fn readUntilDelimiterBuffer(self: &Self, buffer: &Buffer, delimiter: u8, max_size: usize) !void {
414 try buf.resize(0);
454415
455 /// Returns the number of bytes read. If the number read is smaller than buf.len, it
456 /// means the stream reached the end. Reaching the end of a stream is not an error
457 /// condition.
458 pub fn read(self: &InStream, buffer: []u8) %usize {
459 return self.readFn(self, buffer);
460 }
416 while (true) {
417 var byte: u8 = try self.readByte();
461418
462 /// Same as `read` but end of stream returns `error.EndOfStream`.
463 pub fn readNoEof(self: &InStream, buf: []u8) %void {
464 const amt_read = try self.read(buf);
465 if (amt_read < buf.len) return error.EndOfStream;
466 }
419 if (byte == delimiter) {
420 return;
421 }
467422
468 /// Reads 1 byte from the stream or returns `error.EndOfStream`.
469 pub fn readByte(self: &InStream) %u8 {
470 var result: [1]u8 = undefined;
471 try self.readNoEof(result[0..]);
472 return result[0];
473 }
423 if (buf.len() == max_size) {
424 return error.StreamTooLong;
425 }
474426
475 /// Same as `readByte` except the returned byte is signed.
476 pub fn readByteSigned(self: &InStream) %i8 {
477 return @bitCast(i8, try self.readByte());
478 }
427 try buf.appendByte(byte);
428 }
429 }
479430
480 pub fn readIntLe(self: &InStream, comptime T: type) %T {
481 return self.readInt(builtin.Endian.Little, T);
482 }
431 /// Allocates enough memory to read until `delimiter`. If the allocated
432 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.
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 {
485 return self.readInt(builtin.Endian.Big, T);
486 }
445 /// Returns the number of bytes read. If the number read is smaller than buf.len, it
446 /// means the stream reached the end. Reaching the end of a stream is not an error
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 {
489 var bytes: [@sizeOf(T)]u8 = undefined;
490 try self.readNoEof(bytes[0..]);
491 return mem.readInt(bytes, T, endian);
492 }
452 /// Same as `read` but end of stream returns `error.EndOfStream`.
453 pub fn readNoEof(self: &Self, buf: []u8) !void {
454 const amt_read = try self.read(buf);
455 if (amt_read < buf.len) return error.EndOfStream;
456 }
493457
494 pub fn readVarInt(self: &InStream, endian: builtin.Endian, comptime T: type, size: usize) %T {
495 assert(size <= @sizeOf(T));
496 assert(size <= 8);
497 var input_buf: [8]u8 = undefined;
498 const input_slice = input_buf[0..size];
499 try self.readNoEof(input_slice);
500 return mem.readInt(input_slice, T, endian);
501 }
458 /// Reads 1 byte from the stream or returns `error.EndOfStream`.
459 pub fn readByte(self: &Self) !u8 {
460 var result: [1]u8 = undefined;
461 try self.readNoEof(result[0..]);
462 return result[0];
463 }
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 {
507 writeFn: fn(self: &OutStream, bytes: []const u8) %void,
474 pub fn readIntBe(self: &Self, comptime T: type) !T {
475 return self.readInt(builtin.Endian.Big, T);
476 }
508477
509 pub fn print(self: &OutStream, comptime format: []const u8, args: ...) %void {
510 return std.fmt.format(self, self.writeFn, format, args);
511 }
478 pub fn readInt(self: &Self, endian: builtin.Endian, comptime T: type) !T {
479 var bytes: [@sizeOf(T)]u8 = undefined;
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 {
514 return self.writeFn(self, bytes);
515 }
484 pub fn readVarInt(self: &Self, endian: builtin.Endian, comptime T: type, size: usize) !T {
485 assert(size <= @sizeOf(T));
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 {
518 const slice = (&byte)[0..1];
519 return self.writeFn(self, slice);
520 }
495pub fn OutStream(comptime Error: type) type {
496 return struct {
497 const Self = this;
498
499 writeFn: fn(self: &Self, bytes: []const u8) Error!void,
521500
522 pub fn writeByteNTimes(self: &OutStream, byte: u8, n: usize) %void {
523 const slice = (&byte)[0..1];
524 var i: usize = 0;
525 while (i < n) : (i += 1) {
526 try self.writeFn(self, slice);
501 pub fn print(self: &Self, comptime format: []const u8, args: ...) !void {
502 return std.fmt.format(self, error, self.writeFn, format, args);
503 }
504
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);
527512 }
528 }
529};
513
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
531524/// `path` may need to be copied in memory to add a null terminating byte. In this case
532525/// a fixed size buffer of size `std.os.max_noalloc_path_len` is an attempted solution. If the fixed
533526/// size buffer is too small, and the provided allocator is null, `error.NameTooLong` is returned.
534527/// 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 {
536529 var file = try File.openWrite(path, allocator);
537530 defer file.close();
538531 try file.write(data);
539532}
540533
541534/// 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 {
543536 return readFileAllocExtra(path, allocator, 0);
544537}
545538/// On success, caller owns returned buffer.
546539/// 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 {
548541 var file = try File.openRead(path, allocator);
549542 defer file.close();
550543
......@@ -557,21 +550,24 @@ pub fn readFileAllocExtra(path: []const u8, allocator: &mem.Allocator, extra_len
557550 return buf;
558551}
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 {
563558 return struct {
564559 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
570566 buffer: [buffer_size]u8,
571567 start_index: usize,
572568 end_index: usize,
573569
574 pub fn init(unbuffered_in_stream: &InStream) Self {
570 pub fn init(unbuffered_in_stream: &Stream) Self {
575571 return Self {
576572 .unbuffered_in_stream = unbuffered_in_stream,
577573 .buffer = undefined,
......@@ -583,13 +579,13 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize) type {
583579 .start_index = buffer_size,
584580 .end_index = buffer_size,
585581
586 .stream = InStream {
582 .stream = Stream {
587583 .readFn = readFn,
588584 },
589585 };
590586 }
591587
592 fn readFn(in_stream: &InStream, dest: []u8) %usize {
588 fn readFn(in_stream: &Stream, dest: []u8) !usize {
593589 const self = @fieldParentPtr(Self, "stream", in_stream);
594590
595591 var dest_index: usize = 0;
......@@ -628,31 +624,34 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize) type {
628624 };
629625}
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 {
634632 return struct {
635633 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
641640 buffer: [buffer_size]u8,
642641 index: usize,
643642
644 pub fn init(unbuffered_out_stream: &OutStream) Self {
643 pub fn init(unbuffered_out_stream: &Stream) Self {
645644 return Self {
646645 .unbuffered_out_stream = unbuffered_out_stream,
647646 .buffer = undefined,
648647 .index = 0,
649 .stream = OutStream {
648 .stream = Stream {
650649 .writeFn = writeFn,
651650 },
652651 };
653652 }
654653
655 pub fn flush(self: &Self) %void {
654 pub fn flush(self: &Self) !void {
656655 if (self.index == 0)
657656 return;
658657
......@@ -660,7 +659,7 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize) type {
660659 self.index = 0;
661660 }
662661
663 fn writeFn(out_stream: &OutStream, bytes: []const u8) %void {
662 fn writeFn(out_stream: &Stream, bytes: []const u8) !void {
664663 const self = @fieldParentPtr(Self, "stream", out_stream);
665664
666665 if (bytes.len >= self.buffer.len) {
......@@ -687,18 +686,21 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize) type {
687686/// Implementation of OutStream trait for Buffer
688687pub const BufferOutStream = struct {
689688 buffer: &Buffer,
690 stream: OutStream,
689 stream: Stream,
690
691 pub const Error = error{OutOfMemory};
692 pub const Stream = OutStream(Error);
691693
692694 pub fn init(buffer: &Buffer) BufferOutStream {
693695 return BufferOutStream {
694696 .buffer = buffer,
695 .stream = OutStream {
697 .stream = Stream {
696698 .writeFn = writeFn,
697699 },
698700 };
699701 }
700702
701 fn writeFn(out_stream: &OutStream, bytes: []const u8) %void {
703 fn writeFn(out_stream: &Stream, bytes: []const u8) !void {
702704 const self = @fieldParentPtr(BufferOutStream, "stream", out_stream);
703705 return self.buffer.append(bytes);
704706 }
std/io_test.zig+2-2
......@@ -17,7 +17,7 @@ test "write a file, read it, then delete it" {
1717 defer file.close();
1818
1919 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);
2121 const st = &buf_stream.stream;
2222 try st.print("begin");
2323 try st.write(data[0..]);
......@@ -33,7 +33,7 @@ test "write a file, read it, then delete it" {
3333 assert(file_size == expected_file_size);
3434
3535 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);
3737 const st = &buf_stream.stream;
3838 const contents = try st.readAllAlloc(allocator, 2 * 1024);
3939 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
190190 ///
191191 /// Returns:
192192 /// A pointer to the new node.
193 pub fn allocateNode(list: &Self, allocator: &Allocator) %&Node {
193 pub fn allocateNode(list: &Self, allocator: &Allocator) !&Node {
194194 comptime assert(!isIntrusive());
195195 return allocator.create(Node);
196196 }
......@@ -213,7 +213,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
213213 ///
214214 /// Returns:
215215 /// 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 {
217217 comptime assert(!isIntrusive());
218218 var node = try list.allocateNode(allocator);
219219 *node = Node.init(data);
std/math/index.zig+13-31
......@@ -191,30 +191,26 @@ test "math.max" {
191191 assert(max(i32(-1), i32(2)) == 2);
192192}
193193
194error Overflow;
195pub fn mul(comptime T: type, a: T, b: T) %T {
194pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) {
196195 var answer: T = undefined;
197196 return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer;
198197}
199198
200error Overflow;
201pub fn add(comptime T: type, a: T, b: T) %T {
199pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) {
202200 var answer: T = undefined;
203201 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
204202}
205203
206error Overflow;
207pub fn sub(comptime T: type, a: T, b: T) %T {
204pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) {
208205 var answer: T = undefined;
209206 return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer;
210207}
211208
212pub fn negate(x: var) %@typeOf(x) {
209pub fn negate(x: var) !@typeOf(x) {
213210 return sub(@typeOf(x), 0, x);
214211}
215212
216error Overflow;
217pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) %T {
213pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {
218214 var answer: T = undefined;
219215 return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer;
220216}
......@@ -323,8 +319,7 @@ fn testOverflow() void {
323319}
324320
325321
326error Overflow;
327pub fn absInt(x: var) %@typeOf(x) {
322pub fn absInt(x: var) !@typeOf(x) {
328323 const T = @typeOf(x);
329324 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
330325 comptime assert(T.is_signed); // must pass a signed integer to absInt
......@@ -347,9 +342,7 @@ fn testAbsInt() void {
347342
348343pub const absFloat = @import("fabs.zig").fabs;
349344
350error DivisionByZero;
351error Overflow;
352pub fn divTrunc(comptime T: type, numerator: T, denominator: T) %T {
345pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {
353346 @setRuntimeSafety(false);
354347 if (denominator == 0)
355348 return error.DivisionByZero;
......@@ -372,9 +365,7 @@ fn testDivTrunc() void {
372365 assert((divTrunc(f32, -5.0, 3.0) catch unreachable) == -1.0);
373366}
374367
375error DivisionByZero;
376error Overflow;
377pub fn divFloor(comptime T: type, numerator: T, denominator: T) %T {
368pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T {
378369 @setRuntimeSafety(false);
379370 if (denominator == 0)
380371 return error.DivisionByZero;
......@@ -397,10 +388,7 @@ fn testDivFloor() void {
397388 assert((divFloor(f32, -5.0, 3.0) catch unreachable) == -2.0);
398389}
399390
400error DivisionByZero;
401error Overflow;
402error UnexpectedRemainder;
403pub fn divExact(comptime T: type, numerator: T, denominator: T) %T {
391pub fn divExact(comptime T: type, numerator: T, denominator: T) !T {
404392 @setRuntimeSafety(false);
405393 if (denominator == 0)
406394 return error.DivisionByZero;
......@@ -428,9 +416,7 @@ fn testDivExact() void {
428416 if (divExact(f32, 5.0, 2.0)) |_| unreachable else |err| assert(err == error.UnexpectedRemainder);
429417}
430418
431error DivisionByZero;
432error NegativeDenominator;
433pub fn mod(comptime T: type, numerator: T, denominator: T) %T {
419pub fn mod(comptime T: type, numerator: T, denominator: T) !T {
434420 @setRuntimeSafety(false);
435421 if (denominator == 0)
436422 return error.DivisionByZero;
......@@ -455,9 +441,7 @@ fn testMod() void {
455441 if (mod(f32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);
456442}
457443
458error DivisionByZero;
459error NegativeDenominator;
460pub fn rem(comptime T: type, numerator: T, denominator: T) %T {
444pub fn rem(comptime T: type, numerator: T, denominator: T) !T {
461445 @setRuntimeSafety(false);
462446 if (denominator == 0)
463447 return error.DivisionByZero;
......@@ -505,8 +489,7 @@ test "math.absCast" {
505489
506490/// Returns the negation of the integer parameter.
507491/// Result is a signed integer.
508error Overflow;
509pub fn negateCast(x: var) %@IntType(true, @typeOf(x).bit_count) {
492pub fn negateCast(x: var) !@IntType(true, @typeOf(x).bit_count) {
510493 if (@typeOf(x).is_signed)
511494 return negate(x);
512495
......@@ -532,8 +515,7 @@ test "math.negateCast" {
532515
533516/// Cast an integer to a different integer type. If the value doesn't fit,
534517/// return an error.
535error Overflow;
536pub fn cast(comptime T: type, x: var) %T {
518pub fn cast(comptime T: type, x: var) !T {
537519 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer
538520 if (x > @maxValue(T)) {
539521 return error.Overflow;
std/mem.zig+15-15
......@@ -4,13 +4,13 @@ const assert = debug.assert;
44const math = std.math;
55const builtin = @import("builtin");
66
7error OutOfMemory;
8
97pub const Allocator = struct {
8 const Error = error {OutOfMemory};
9
1010 /// Allocate byte_count bytes and return them in a slice, with the
1111 /// slice's pointer aligned at least to alignment bytes.
1212 /// 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
1515 /// If `new_byte_count > old_mem.len`:
1616 /// * `old_mem.len` is the same as what was returned from allocFn or reallocFn.
......@@ -21,12 +21,12 @@ pub const Allocator = struct {
2121 /// * alignment <= alignment of old_mem.ptr
2222 ///
2323 /// 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
2626 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
2727 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 {
3030 const slice = try self.alloc(T, 1);
3131 return &slice[0];
3232 }
......@@ -35,14 +35,14 @@ pub const Allocator = struct {
3535 self.free(ptr[0..1]);
3636 }
3737
38 fn alloc(self: &Allocator, comptime T: type, n: usize) %[]T {
38 fn alloc(self: &Allocator, comptime T: type, n: usize) ![]T {
3939 return self.alignedAlloc(T, @alignOf(T), n);
4040 }
4141
4242 fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29,
43 n: usize) %[]align(alignment) T
43 n: usize) ![]align(alignment) T
4444 {
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;
4646 const byte_slice = try self.allocFn(self, byte_count, alignment);
4747 // This loop should get optimized out in ReleaseFast mode
4848 for (byte_slice) |*byte| {
......@@ -51,19 +51,19 @@ pub const Allocator = struct {
5151 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
5252 }
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 {
5555 return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
5656 }
5757
5858 fn alignedRealloc(self: &Allocator, comptime T: type, comptime alignment: u29,
59 old_mem: []align(alignment) T, n: usize) %[]align(alignment) T
59 old_mem: []align(alignment) T, n: usize) ![]align(alignment) T
6060 {
6161 if (old_mem.len == 0) {
6262 return self.alloc(T, n);
6363 }
6464
6565 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;
6767 const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment);
6868 // This loop should get optimized out in ReleaseFast mode
6969 for (byte_slice[old_byte_slice.len..]) |*byte| {
......@@ -123,7 +123,7 @@ pub const FixedBufferAllocator = struct {
123123 };
124124 }
125125
126 fn alloc(allocator: &Allocator, n: usize, alignment: u29) %[]u8 {
126 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
127127 const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator);
128128 const addr = @ptrToInt(&self.buffer[self.end_index]);
129129 const rem = @rem(addr, alignment);
......@@ -138,7 +138,7 @@ pub const FixedBufferAllocator = struct {
138138 return result;
139139 }
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 {
142142 if (new_size <= old_mem.len) {
143143 return old_mem[0..new_size];
144144 } else {
......@@ -197,7 +197,7 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
197197}
198198
199199/// 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 {
201201 const new_buf = try allocator.alloc(T, m.len);
202202 copy(T, new_buf, m);
203203 return new_buf;
......@@ -428,7 +428,7 @@ const SplitIterator = struct {
428428
429429/// Naively combines a series of strings with a separator.
430430/// 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 {
432432 comptime assert(strings.len >= 1);
433433 var total_strings_len: usize = strings.len; // 1 sep per string
434434 {
std/net.zig+9-25
......@@ -5,19 +5,10 @@ const endian = std.endian;
55
66// 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
178const Connection = struct {
189 socket_fd: i32,
1910
20 pub fn send(c: Connection, buf: []const u8) %usize {
11 pub fn send(c: Connection, buf: []const u8) !usize {
2112 const send_ret = linux.sendto(c.socket_fd, buf.ptr, buf.len, 0, null, 0);
2213 const send_err = linux.getErrno(send_ret);
2314 switch (send_err) {
......@@ -31,7 +22,7 @@ const Connection = struct {
3122 }
3223 }
3324
34 pub fn recv(c: Connection, buf: []u8) %[]u8 {
25 pub fn recv(c: Connection, buf: []u8) ![]u8 {
3526 const recv_ret = linux.recvfrom(c.socket_fd, buf.ptr, buf.len, 0, null, null);
3627 const recv_err = linux.getErrno(recv_ret);
3728 switch (recv_err) {
......@@ -48,7 +39,7 @@ const Connection = struct {
4839 }
4940 }
5041
51 pub fn close(c: Connection) %void {
42 pub fn close(c: Connection) !void {
5243 switch (linux.getErrno(linux.close(c.socket_fd))) {
5344 0 => return,
5445 linux.EBADF => unreachable,
......@@ -66,7 +57,7 @@ const Address = struct {
6657 sort_key: i32,
6758};
6859
69pub fn lookup(hostname: []const u8, out_addrs: []Address) %[]Address {
60pub fn lookup(hostname: []const u8, out_addrs: []Address) ![]Address {
7061 if (hostname.len == 0) {
7162
7263 unreachable; // TODO
......@@ -75,7 +66,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) %[]Address {
7566 unreachable; // TODO
7667}
7768
78pub fn connectAddr(addr: &Address, port: u16) %Connection {
69pub fn connectAddr(addr: &Address, port: u16) !Connection {
7970 const socket_ret = linux.socket(addr.family, linux.SOCK_STREAM, linux.PROTO_tcp);
8071 const socket_err = linux.getErrno(socket_ret);
8172 if (socket_err > 0) {
......@@ -118,7 +109,7 @@ pub fn connectAddr(addr: &Address, port: u16) %Connection {
118109 };
119110}
120111
121pub fn connect(hostname: []const u8, port: u16) %Connection {
112pub fn connect(hostname: []const u8, port: u16) !Connection {
122113 var addrs_buf: [1]Address = undefined;
123114 const addrs_slice = try lookup(hostname, addrs_buf[0..]);
124115 const main_addr = &addrs_slice[0];
......@@ -126,9 +117,7 @@ pub fn connect(hostname: []const u8, port: u16) %Connection {
126117 return connectAddr(main_addr, port);
127118}
128119
129error InvalidIpLiteral;
130
131pub fn parseIpLiteral(buf: []const u8) %Address {
120pub fn parseIpLiteral(buf: []const u8) !Address {
132121
133122 return error.InvalidIpLiteral;
134123}
......@@ -146,12 +135,7 @@ fn hexDigit(c: u8) u8 {
146135 }
147136}
148137
149error InvalidChar;
150error Overflow;
151error JunkAtEnd;
152error Incomplete;
153
154fn parseIp6(buf: []const u8) %Address {
138fn parseIp6(buf: []const u8) !Address {
155139 var result: Address = undefined;
156140 result.family = linux.AF_INET6;
157141 result.scope_id = 0;
......@@ -232,7 +216,7 @@ fn parseIp6(buf: []const u8) %Address {
232216 return error.Incomplete;
233217}
234218
235fn parseIp4(buf: []const u8) %u32 {
219fn parseIp4(buf: []const u8) !u32 {
236220 var result: u32 = undefined;
237221 const out_ptr = ([]u8)((&result)[0..1]);
238222
std/os/child_process.zig+49-34
......@@ -13,10 +13,6 @@ const builtin = @import("builtin");
1313const Os = builtin.Os;
1414const LinkedList = std.LinkedList;
1515
16error PermissionDenied;
17error ProcessNotFound;
18error InvalidName;
19
2016var children_nodes = LinkedList(&ChildProcess).init();
2117
2218const is_windows = builtin.os == Os.windows;
......@@ -32,7 +28,7 @@ pub const ChildProcess = struct {
3228 pub stdout: ?io.File,
3329 pub stderr: ?io.File,
3430
35 pub term: ?%Term,
31 pub term: ?(SpawnError!Term),
3632
3733 pub argv: []const []const u8,
3834
......@@ -58,6 +54,25 @@ pub const ChildProcess = struct {
5854 err_pipe: if (is_windows) void else [2]i32,
5955 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
6176 pub const Term = union(enum) {
6277 Exited: i32,
6378 Signal: i32,
......@@ -74,7 +89,7 @@ pub const ChildProcess = struct {
7489
7590 /// First argument in argv is the executable.
7691 /// 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 {
7893 const child = try allocator.create(ChildProcess);
7994 errdefer allocator.destroy(child);
8095
......@@ -103,7 +118,7 @@ pub const ChildProcess = struct {
103118 return child;
104119 }
105120
106 pub fn setUserName(self: &ChildProcess, name: []const u8) %void {
121 pub fn setUserName(self: &ChildProcess, name: []const u8) !void {
107122 const user_info = try os.getUserInfo(name);
108123 self.uid = user_info.uid;
109124 self.gid = user_info.gid;
......@@ -111,7 +126,7 @@ pub const ChildProcess = struct {
111126
112127 /// onTerm can be called before `spawn` returns.
113128 /// On success must call `kill` or `wait`.
114 pub fn spawn(self: &ChildProcess) %void {
129 pub fn spawn(self: &ChildProcess) !void {
115130 if (is_windows) {
116131 return self.spawnWindows();
117132 } else {
......@@ -119,13 +134,13 @@ pub const ChildProcess = struct {
119134 }
120135 }
121136
122 pub fn spawnAndWait(self: &ChildProcess) %Term {
137 pub fn spawnAndWait(self: &ChildProcess) !Term {
123138 try self.spawn();
124139 return self.wait();
125140 }
126141
127142 /// Forcibly terminates child process and then cleans up all resources.
128 pub fn kill(self: &ChildProcess) %Term {
143 pub fn kill(self: &ChildProcess) !Term {
129144 if (is_windows) {
130145 return self.killWindows(1);
131146 } else {
......@@ -133,7 +148,7 @@ pub const ChildProcess = struct {
133148 }
134149 }
135150
136 pub fn killWindows(self: &ChildProcess, exit_code: windows.UINT) %Term {
151 pub fn killWindows(self: &ChildProcess, exit_code: windows.UINT) !Term {
137152 if (self.term) |term| {
138153 self.cleanupStreams();
139154 return term;
......@@ -145,11 +160,11 @@ pub const ChildProcess = struct {
145160 else => os.unexpectedErrorWindows(err),
146161 };
147162 }
148 self.waitUnwrappedWindows();
163 try self.waitUnwrappedWindows();
149164 return ??self.term;
150165 }
151166
152 pub fn killPosix(self: &ChildProcess) %Term {
167 pub fn killPosix(self: &ChildProcess) !Term {
153168 block_SIGCHLD();
154169 defer restore_SIGCHLD();
155170
......@@ -172,7 +187,7 @@ pub const ChildProcess = struct {
172187 }
173188
174189 /// 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 {
176191 if (is_windows) {
177192 return self.waitWindows();
178193 } else {
......@@ -189,7 +204,7 @@ pub const ChildProcess = struct {
189204 /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.
190205 /// If it succeeds, the caller owns result.stdout and result.stderr memory.
191206 pub fn exec(allocator: &mem.Allocator, argv: []const []const u8, cwd: ?[]const u8,
192 env_map: ?&const BufMap, max_output_size: usize) %ExecResult
207 env_map: ?&const BufMap, max_output_size: usize) !ExecResult
193208 {
194209 const child = try ChildProcess.init(argv, allocator);
195210 defer child.deinit();
......@@ -220,7 +235,7 @@ pub const ChildProcess = struct {
220235 };
221236 }
222237
223 fn waitWindows(self: &ChildProcess) %Term {
238 fn waitWindows(self: &ChildProcess) !Term {
224239 if (self.term) |term| {
225240 self.cleanupStreams();
226241 return term;
......@@ -230,7 +245,7 @@ pub const ChildProcess = struct {
230245 return ??self.term;
231246 }
232247
233 fn waitPosix(self: &ChildProcess) %Term {
248 fn waitPosix(self: &ChildProcess) !Term {
234249 block_SIGCHLD();
235250 defer restore_SIGCHLD();
236251
......@@ -247,10 +262,10 @@ pub const ChildProcess = struct {
247262 self.allocator.destroy(self);
248263 }
249264
250 fn waitUnwrappedWindows(self: &ChildProcess) %void {
265 fn waitUnwrappedWindows(self: &ChildProcess) !void {
251266 const result = os.windowsWaitSingle(self.handle, windows.INFINITE);
252267
253 self.term = (%Term)(x: {
268 self.term = (SpawnError!Term)(x: {
254269 var exit_code: windows.DWORD = undefined;
255270 if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {
256271 break :x Term { .Unknown = 0 };
......@@ -295,7 +310,7 @@ pub const ChildProcess = struct {
295310 if (self.stderr) |*stderr| { stderr.close(); self.stderr = null; }
296311 }
297312
298 fn cleanupAfterWait(self: &ChildProcess, status: i32) %Term {
313 fn cleanupAfterWait(self: &ChildProcess, status: i32) !Term {
299314 children_nodes.remove(&self.llnode);
300315
301316 defer {
......@@ -313,7 +328,7 @@ pub const ChildProcess = struct {
313328 // Here we potentially return the fork child's error
314329 // from the parent pid.
315330 if (err_int != @maxValue(ErrInt)) {
316 return error(err_int);
331 return SpawnError(err_int);
317332 }
318333
319334 return statusToTerm(status);
......@@ -331,7 +346,7 @@ pub const ChildProcess = struct {
331346 ;
332347 }
333348
334 fn spawnPosix(self: &ChildProcess) %void {
349 fn spawnPosix(self: &ChildProcess) !void {
335350 // TODO atomically set a flag saying that we already did this
336351 install_SIGCHLD_handler();
337352
......@@ -440,7 +455,7 @@ pub const ChildProcess = struct {
440455 if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); }
441456 }
442457
443 fn spawnWindows(self: &ChildProcess) %void {
458 fn spawnWindows(self: &ChildProcess) !void {
444459 const saAttr = windows.SECURITY_ATTRIBUTES {
445460 .nLength = @sizeOf(windows.SECURITY_ATTRIBUTES),
446461 .bInheritHandle = windows.TRUE,
......@@ -623,7 +638,7 @@ pub const ChildProcess = struct {
623638 if (self.stdout_behavior == StdIo.Pipe) { os.close(??g_hChildStd_OUT_Wr); }
624639 }
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 {
627642 switch (stdio) {
628643 StdIo.Pipe => try os.posixDup2(pipe_fd, std_fileno),
629644 StdIo.Close => os.close(std_fileno),
......@@ -635,7 +650,7 @@ pub const ChildProcess = struct {
635650};
636651
637652fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?&u8,
638 lpStartupInfo: &windows.STARTUPINFOA, lpProcessInformation: &windows.PROCESS_INFORMATION) %void
653 lpStartupInfo: &windows.STARTUPINFOA, lpProcessInformation: &windows.PROCESS_INFORMATION) !void
639654{
640655 if (windows.CreateProcessA(app_name, cmd_line, null, null, windows.TRUE, 0,
641656 @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: ?
655670
656671/// Caller must dealloc.
657672/// 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 {
659674 var buf = try Buffer.initSize(allocator, 0);
660675 defer buf.deinit();
661676
......@@ -700,7 +715,7 @@ fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void {
700715// a namespace field lookup
701716const 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 {
704719 if (windows.CreatePipe(rd, wr, sattr, 0) == 0) {
705720 const err = windows.GetLastError();
706721 return switch (err) {
......@@ -709,7 +724,7 @@ fn windowsMakePipe(rd: &windows.HANDLE, wr: &windows.HANDLE, sattr: &const SECUR
709724 }
710725}
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 {
713728 if (windows.SetHandleInformation(h, mask, flags) == 0) {
714729 const err = windows.GetLastError();
715730 return switch (err) {
......@@ -718,7 +733,7 @@ fn windowsSetHandleInfo(h: windows.HANDLE, mask: windows.DWORD, flags: windows.D
718733 }
719734}
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 {
722737 var rd_h: windows.HANDLE = undefined;
723738 var wr_h: windows.HANDLE = undefined;
724739 try windowsMakePipe(&rd_h, &wr_h, sattr);
......@@ -728,7 +743,7 @@ fn windowsMakePipeIn(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const S
728743 *wr = wr_h;
729744}
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 {
732747 var rd_h: windows.HANDLE = undefined;
733748 var wr_h: windows.HANDLE = undefined;
734749 try windowsMakePipe(&rd_h, &wr_h, sattr);
......@@ -738,7 +753,7 @@ fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const
738753 *wr = wr_h;
739754}
740755
741fn makePipe() %[2]i32 {
756fn makePipe() ![2]i32 {
742757 var fds: [2]i32 = undefined;
743758 const err = posix.getErrno(posix.pipe(&fds));
744759 if (err > 0) {
......@@ -757,20 +772,20 @@ fn destroyPipe(pipe: &const [2]i32) void {
757772
758773// Child of fork calls this to report an error to the fork parent.
759774// Then the child exits.
760fn forkChildErrReport(fd: i32, err: error) noreturn {
775fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
761776 _ = writeIntFd(fd, ErrInt(err));
762777 posix.exit(1);
763778}
764779
765780const ErrInt = @IntType(false, @sizeOf(error) * 8);
766781
767fn writeIntFd(fd: i32, value: ErrInt) %void {
782fn writeIntFd(fd: i32, value: ErrInt) !void {
768783 var bytes: [@sizeOf(ErrInt)]u8 = undefined;
769784 mem.writeInt(bytes[0..], value, builtin.endian);
770785 os.posixWrite(fd, bytes[0..]) catch return error.SystemResources;
771786}
772787
773fn readIntFd(fd: i32) %ErrInt {
788fn readIntFd(fd: i32) !ErrInt {
774789 var bytes: [@sizeOf(ErrInt)]u8 = undefined;
775790 os.posixRead(fd, bytes[0..]) catch return error.SystemResources;
776791 return mem.readInt(bytes[0..], ErrInt, builtin.endian);
std/os/get_user_id.zig+2-5
......@@ -9,7 +9,7 @@ pub const UserInfo = struct {
99};
1010
1111/// POSIX function which gets a uid from username.
12pub fn getUserInfo(name: []const u8) %UserInfo {
12pub fn getUserInfo(name: []const u8) !UserInfo {
1313 return switch (builtin.os) {
1414 Os.linux, Os.macosx, Os.ios => posixGetUserInfo(name),
1515 else => @compileError("Unsupported OS"),
......@@ -24,13 +24,10 @@ const State = enum {
2424 ReadGroupId,
2525};
2626
27error UserNotFound;
28error CorruptPasswordFile;
29
3027// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else
3128// 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 {
3431 var in_stream = try io.InStream.open("/etc/passwd", null);
3532 defer in_stream.close();
3633
std/os/index.zig+207-118
......@@ -38,6 +38,10 @@ pub const windowsLoadDll = windows_util.windowsLoadDll;
3838pub const windowsUnloadDll = windows_util.windowsUnloadDll;
3939pub 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
4145pub const FileHandle = if (is_windows) windows.HANDLE else i32;
4246
4347const debug = std.debug;
......@@ -57,25 +61,10 @@ const ArrayList = std.ArrayList;
5761const Buffer = std.Buffer;
5862const 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
7564/// Fills `buf` with random bytes. If linking against libc, this calls the
7665/// appropriate OS-specific library call. Otherwise it uses the zig standard
7766/// library implementation.
78pub fn getRandomBytes(buf: []u8) %void {
67pub fn getRandomBytes(buf: []u8) !void {
7968 switch (builtin.os) {
8069 Os.linux => while (true) {
8170 // TODO check libc version and potentially call c.getrandom.
......@@ -188,7 +177,7 @@ pub fn close(handle: FileHandle) void {
188177}
189178
190179/// 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 {
192181 // Linux can return EINVAL when read amount is > 0x7ffff000
193182 // See https://github.com/zig-lang/zig/pull/743#issuecomment-363158274
194183 const max_buf_len = 0x7ffff000;
......@@ -214,17 +203,21 @@ pub fn posixRead(fd: i32, buf: []u8) %void {
214203 }
215204}
216205
217error WouldBlock;
218error FileClosed;
219error DestinationAddressRequired;
220error DiskQuota;
221error FileTooBig;
222error InputOutput;
223error NoSpaceLeft;
224error BrokenPipe;
206pub const PosixWriteError = error {
207 WouldBlock,
208 FileClosed,
209 DestinationAddressRequired,
210 DiskQuota,
211 FileTooBig,
212 InputOutput,
213 NoSpaceLeft,
214 AccessDenied,
215 BrokenPipe,
216 Unexpected,
217};
225218
226219/// 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 {
228221 // Linux can return EINVAL when write amount is > 0x7ffff000
229222 // See https://github.com/zig-lang/zig/pull/743#issuecomment-363165856
230223 const max_bytes_len = 0x7ffff000;
......@@ -238,15 +231,15 @@ pub fn posixWrite(fd: i32, bytes: []const u8) %void {
238231 return switch (write_err) {
239232 posix.EINTR => continue,
240233 posix.EINVAL, posix.EFAULT => unreachable,
241 posix.EAGAIN => error.WouldBlock,
242 posix.EBADF => error.FileClosed,
243 posix.EDESTADDRREQ => error.DestinationAddressRequired,
244 posix.EDQUOT => error.DiskQuota,
245 posix.EFBIG => error.FileTooBig,
246 posix.EIO => error.InputOutput,
247 posix.ENOSPC => error.NoSpaceLeft,
248 posix.EPERM => error.AccessDenied,
249 posix.EPIPE => error.BrokenPipe,
234 posix.EAGAIN => PosixWriteError.WouldBlock,
235 posix.EBADF => PosixWriteError.FileClosed,
236 posix.EDESTADDRREQ => PosixWriteError.DestinationAddressRequired,
237 posix.EDQUOT => PosixWriteError.DiskQuota,
238 posix.EFBIG => PosixWriteError.FileTooBig,
239 posix.EIO => PosixWriteError.InputOutput,
240 posix.ENOSPC => PosixWriteError.NoSpaceLeft,
241 posix.EPERM => PosixWriteError.AccessDenied,
242 posix.EPIPE => PosixWriteError.BrokenPipe,
250243 else => unexpectedErrorPosix(write_err),
251244 };
252245 }
......@@ -254,13 +247,31 @@ pub fn posixWrite(fd: i32, bytes: []const u8) %void {
254247 }
255248}
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
257268/// ::file_path may need to be copied in memory to add a null terminating byte. In this case
258269/// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed
259270/// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned.
260271/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
261272/// Calls POSIX open, keeps trying if it gets interrupted, and translates
262273/// 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 {
264275 var stack_buf: [max_noalloc_path_len]u8 = undefined;
265276 var path0: []u8 = undefined;
266277 var need_free = false;
......@@ -282,7 +293,7 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al
282293 return posixOpenC(path0.ptr, flags, perm);
283294}
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 {
286297 while (true) {
287298 const result = posix.open(file_path, flags, perm);
288299 const err = posix.getErrno(result);
......@@ -292,20 +303,20 @@ pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) %i32 {
292303
293304 posix.EFAULT => unreachable,
294305 posix.EINVAL => unreachable,
295 posix.EACCES => error.AccessDenied,
296 posix.EFBIG, posix.EOVERFLOW => error.FileTooBig,
297 posix.EISDIR => error.IsDir,
298 posix.ELOOP => error.SymLinkLoop,
299 posix.EMFILE => error.ProcessFdQuotaExceeded,
300 posix.ENAMETOOLONG => error.NameTooLong,
301 posix.ENFILE => error.SystemFdQuotaExceeded,
302 posix.ENODEV => error.NoDevice,
303 posix.ENOENT => error.PathNotFound,
304 posix.ENOMEM => error.SystemResources,
305 posix.ENOSPC => error.NoSpaceLeft,
306 posix.ENOTDIR => error.NotDir,
307 posix.EPERM => error.AccessDenied,
308 posix.EEXIST => error.PathAlreadyExists,
306 posix.EACCES => PosixOpenError.AccessDenied,
307 posix.EFBIG, posix.EOVERFLOW => PosixOpenError.FileTooBig,
308 posix.EISDIR => PosixOpenError.IsDir,
309 posix.ELOOP => PosixOpenError.SymLinkLoop,
310 posix.EMFILE => PosixOpenError.ProcessFdQuotaExceeded,
311 posix.ENAMETOOLONG => PosixOpenError.NameTooLong,
312 posix.ENFILE => PosixOpenError.SystemFdQuotaExceeded,
313 posix.ENODEV => PosixOpenError.NoDevice,
314 posix.ENOENT => PosixOpenError.PathNotFound,
315 posix.ENOMEM => PosixOpenError.SystemResources,
316 posix.ENOSPC => PosixOpenError.NoSpaceLeft,
317 posix.ENOTDIR => PosixOpenError.NotDir,
318 posix.EPERM => PosixOpenError.AccessDenied,
319 posix.EEXIST => PosixOpenError.PathAlreadyExists,
309320 else => unexpectedErrorPosix(err),
310321 };
311322 }
......@@ -313,7 +324,7 @@ pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) %i32 {
313324 }
314325}
315326
316pub fn posixDup2(old_fd: i32, new_fd: i32) %void {
327pub fn posixDup2(old_fd: i32, new_fd: i32) !void {
317328 while (true) {
318329 const err = posix.getErrno(posix.dup2(old_fd, new_fd));
319330 if (err > 0) {
......@@ -328,7 +339,7 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) %void {
328339 }
329340}
330341
331pub fn createNullDelimitedEnvMap(allocator: &Allocator, env_map: &const BufMap) %[]?&u8 {
342pub fn createNullDelimitedEnvMap(allocator: &Allocator, env_map: &const BufMap) ![]?&u8 {
332343 const envp_count = env_map.count();
333344 const envp_buf = try allocator.alloc(?&u8, envp_count + 1);
334345 mem.set(?&u8, envp_buf, null);
......@@ -365,7 +376,7 @@ pub fn freeNullDelimitedEnvMap(allocator: &Allocator, envp_buf: []?&u8) void {
365376/// `argv[0]` is the executable path.
366377/// This function also uses the PATH environment variable to get the full path to the executable.
367378pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,
368 allocator: &Allocator) %void
379 allocator: &Allocator) !void
369380{
370381 const argv_buf = try allocator.alloc(?&u8, argv.len + 1);
371382 mem.set(?&u8, argv_buf, null);
......@@ -421,7 +432,19 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,
421432 return posixExecveErrnoToErr(err);
422433}
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 {
425448 assert(err > 0);
426449 return switch (err) {
427450 posix.EFAULT => unreachable,
......@@ -440,7 +463,7 @@ fn posixExecveErrnoToErr(err: usize) error {
440463pub var posix_environ_raw: []&u8 = undefined;
441464
442465/// Caller must free result when done.
443pub fn getEnvMap(allocator: &Allocator) %BufMap {
466pub fn getEnvMap(allocator: &Allocator) !BufMap {
444467 var result = BufMap.init(allocator);
445468 errdefer result.deinit();
446469
......@@ -501,10 +524,8 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 {
501524 return null;
502525}
503526
504error EnvironmentVariableNotFound;
505
506527/// 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 {
508529 if (is_windows) {
509530 const key_with_null = try cstr.addNullByte(allocator, key);
510531 defer allocator.free(key_with_null);
......@@ -538,7 +559,7 @@ pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) %[]u8 {
538559}
539560
540561/// Caller must free the returned memory.
541pub fn getCwd(allocator: &Allocator) %[]u8 {
562pub fn getCwd(allocator: &Allocator) ![]u8 {
542563 switch (builtin.os) {
543564 Os.windows => {
544565 var buf = try allocator.alloc(u8, 256);
......@@ -585,7 +606,9 @@ test "os.getCwd" {
585606 _ = getCwd(debug.global_allocator);
586607}
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 {
589612 if (is_windows) {
590613 return symLinkWindows(allocator, existing_path, new_path);
591614 } else {
......@@ -593,7 +616,12 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con
593616 }
594617}
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 {
597625 const existing_with_null = try cstr.addNullByte(allocator, existing_path);
598626 defer allocator.free(existing_with_null);
599627 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
607635 }
608636}
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 {
611655 const full_buf = try allocator.alloc(u8, existing_path.len + new_path.len + 2);
612656 defer allocator.free(full_buf);
613657
......@@ -644,7 +688,7 @@ const b64_fs_encoder = base64.Base64Encoder.init(
644688 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
645689 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 {
648692 if (symLink(allocator, existing_path, new_path)) {
649693 return;
650694 } else |err| {
......@@ -673,7 +717,7 @@ pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path:
673717
674718}
675719
676pub fn deleteFile(allocator: &Allocator, file_path: []const u8) %void {
720pub fn deleteFile(allocator: &Allocator, file_path: []const u8) !void {
677721 if (builtin.os == Os.windows) {
678722 return deleteFileWindows(allocator, file_path);
679723 } else {
......@@ -681,10 +725,7 @@ pub fn deleteFile(allocator: &Allocator, file_path: []const u8) %void {
681725 }
682726}
683727
684error FileNotFound;
685error AccessDenied;
686
687pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) %void {
728pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) !void {
688729 const buf = try allocator.alloc(u8, file_path.len + 1);
689730 defer allocator.free(buf);
690731
......@@ -702,7 +743,7 @@ pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) %void {
702743 }
703744}
704745
705pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) %void {
746pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) !void {
706747 const buf = try allocator.alloc(u8, file_path.len + 1);
707748 defer allocator.free(buf);
708749
......@@ -729,13 +770,13 @@ pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) %void {
729770}
730771
731772/// 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 {
733774 return copyFileMode(allocator, source_path, dest_path, 0o666);
734775}
735776
736777// TODO instead of accepting a mode argument, use the mode from fstat'ing the source path once open
737778/// 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 {
739780 var rand_buf: [12]u8 = undefined;
740781 const tmp_path = try allocator.alloc(u8, dest_path.len + base64.Base64Encoder.calcSize(rand_buf.len));
741782 defer allocator.free(tmp_path);
......@@ -759,7 +800,7 @@ pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: [
759800 }
760801}
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 {
763804 const full_buf = try allocator.alloc(u8, old_path.len + new_path.len + 2);
764805 defer allocator.free(full_buf);
765806
......@@ -804,7 +845,7 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8)
804845 }
805846}
806847
807pub fn makeDir(allocator: &Allocator, dir_path: []const u8) %void {
848pub fn makeDir(allocator: &Allocator, dir_path: []const u8) !void {
808849 if (is_windows) {
809850 return makeDirWindows(allocator, dir_path);
810851 } else {
......@@ -812,7 +853,7 @@ pub fn makeDir(allocator: &Allocator, dir_path: []const u8) %void {
812853 }
813854}
814855
815pub fn makeDirWindows(allocator: &Allocator, dir_path: []const u8) %void {
856pub fn makeDirWindows(allocator: &Allocator, dir_path: []const u8) !void {
816857 const path_buf = try cstr.addNullByte(allocator, dir_path);
817858 defer allocator.free(path_buf);
818859
......@@ -826,7 +867,7 @@ pub fn makeDirWindows(allocator: &Allocator, dir_path: []const u8) %void {
826867 }
827868}
828869
829pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) %void {
870pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) !void {
830871 const path_buf = try cstr.addNullByte(allocator, dir_path);
831872 defer allocator.free(path_buf);
832873
......@@ -852,7 +893,7 @@ pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) %void {
852893
853894/// Calls makeDir recursively to make an entire path. Returns success if the path
854895/// 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 {
856897 const resolved_path = try path.resolve(allocator, full_path);
857898 defer allocator.free(resolved_path);
858899
......@@ -890,7 +931,7 @@ pub fn makePath(allocator: &Allocator, full_path: []const u8) %void {
890931
891932/// Returns ::error.DirNotEmpty if the directory is not empty.
892933/// 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 {
894935 const path_buf = try allocator.alloc(u8, dir_path.len + 1);
895936 defer allocator.free(path_buf);
896937
......@@ -919,24 +960,68 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) %void {
919960/// removes it. If it cannot be removed because it is a non-empty directory,
920961/// this function recursively removes its entries and then tries again.
921962// 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 {
923986 start_over: while (true) {
924987 // First, try deleting the item as a file. This way we don't follow sym links.
925988 if (deleteFile(allocator, full_path)) {
926989 return;
927 } else |err| {
928 if (err == error.FileNotFound)
929 return;
930 if (err != error.IsDir)
931 return err;
990 } else |err| switch (err) {
991 error.FileNotFound => return,
992 error.IsDir => {},
993
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,
9321005 }
9331006 {
934 var dir = Dir.open(allocator, full_path) catch |err| {
935 if (err == error.FileNotFound)
936 return;
937 if (err == error.NotDir)
938 continue :start_over;
939 return err;
1007 var dir = Dir.open(allocator, full_path) catch |err| switch (err) {
1008 error.NotDir => continue :start_over,
1009
1010 error.OutOfMemory,
1011 error.AccessDenied,
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,
9401025 };
9411026 defer dir.close();
9421027
......@@ -988,7 +1073,7 @@ pub const Dir = struct {
9881073 };
9891074 };
9901075
991 pub fn open(allocator: &Allocator, dir_path: []const u8) %Dir {
1076 pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir {
9921077 const fd = try posixOpen(dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0, allocator);
9931078 return Dir {
9941079 .allocator = allocator,
......@@ -1006,7 +1091,7 @@ pub const Dir = struct {
10061091
10071092 /// Memory such as file names referenced in this returned entry becomes invalid
10081093 /// 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 {
10101095 start_over: while (true) {
10111096 if (self.index >= self.end_index) {
10121097 if (self.buf.len == 0) {
......@@ -1063,7 +1148,7 @@ pub const Dir = struct {
10631148 }
10641149};
10651150
1066pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) %void {
1151pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) !void {
10671152 const path_buf = try allocator.alloc(u8, dir_path.len + 1);
10681153 defer allocator.free(path_buf);
10691154
......@@ -1087,7 +1172,7 @@ pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) %void {
10871172}
10881173
10891174/// Read value of a symbolic link.
1090pub fn readLink(allocator: &Allocator, pathname: []const u8) %[]u8 {
1175pub fn readLink(allocator: &Allocator, pathname: []const u8) ![]u8 {
10911176 const path_buf = try allocator.alloc(u8, pathname.len + 1);
10921177 defer allocator.free(path_buf);
10931178
......@@ -1164,11 +1249,7 @@ test "os.sleep" {
11641249 sleep(0, 1);
11651250}
11661251
1167error ResourceLimitReached;
1168error InvalidUserId;
1169error PermissionDenied;
1170
1171pub fn posix_setuid(uid: u32) %void {
1252pub fn posix_setuid(uid: u32) !void {
11721253 const err = posix.getErrno(posix.setuid(uid));
11731254 if (err == 0) return;
11741255 return switch (err) {
......@@ -1179,7 +1260,7 @@ pub fn posix_setuid(uid: u32) %void {
11791260 };
11801261}
11811262
1182pub fn posix_setreuid(ruid: u32, euid: u32) %void {
1263pub fn posix_setreuid(ruid: u32, euid: u32) !void {
11831264 const err = posix.getErrno(posix.setreuid(ruid, euid));
11841265 if (err == 0) return;
11851266 return switch (err) {
......@@ -1190,7 +1271,7 @@ pub fn posix_setreuid(ruid: u32, euid: u32) %void {
11901271 };
11911272}
11921273
1193pub fn posix_setgid(gid: u32) %void {
1274pub fn posix_setgid(gid: u32) !void {
11941275 const err = posix.getErrno(posix.setgid(gid));
11951276 if (err == 0) return;
11961277 return switch (err) {
......@@ -1201,7 +1282,7 @@ pub fn posix_setgid(gid: u32) %void {
12011282 };
12021283}
12031284
1204pub fn posix_setregid(rgid: u32, egid: u32) %void {
1285pub fn posix_setregid(rgid: u32, egid: u32) !void {
12051286 const err = posix.getErrno(posix.setregid(rgid, egid));
12061287 if (err == 0) return;
12071288 return switch (err) {
......@@ -1212,8 +1293,12 @@ pub fn posix_setregid(rgid: u32, egid: u32) %void {
12121293 };
12131294}
12141295
1215error NoStdHandles;
1216pub fn windowsGetStdHandle(handle_id: windows.DWORD) %windows.HANDLE {
1296pub const WindowsGetStdHandleErrs = error {
1297 NoStdHandles,
1298 Unexpected,
1299};
1300
1301pub fn windowsGetStdHandle(handle_id: windows.DWORD) WindowsGetStdHandleErrs!windows.HANDLE {
12171302 if (windows.GetStdHandle(handle_id)) |handle| {
12181303 if (handle == windows.INVALID_HANDLE_VALUE) {
12191304 const err = windows.GetLastError();
......@@ -1267,6 +1352,8 @@ pub const ArgIteratorWindows = struct {
12671352 quote_count: usize,
12681353 seen_quote_count: usize,
12691354
1355 pub const NextError = error{OutOfMemory};
1356
12701357 pub fn init() ArgIteratorWindows {
12711358 return initWithCmdLine(windows.GetCommandLineA());
12721359 }
......@@ -1282,7 +1369,7 @@ pub const ArgIteratorWindows = struct {
12821369 }
12831370
12841371 /// 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) {
12861373 // march forward over whitespace
12871374 while (true) : (self.index += 1) {
12881375 const byte = self.cmd_line[self.index];
......@@ -1335,7 +1422,7 @@ pub const ArgIteratorWindows = struct {
13351422 }
13361423 }
13371424
1338 fn internalNext(self: &ArgIteratorWindows, allocator: &Allocator) %[]u8 {
1425 fn internalNext(self: &ArgIteratorWindows, allocator: &Allocator) NextError![]u8 {
13391426 var buf = try Buffer.initSize(allocator, 0);
13401427 defer buf.deinit();
13411428
......@@ -1379,7 +1466,7 @@ pub const ArgIteratorWindows = struct {
13791466 }
13801467 }
13811468
1382 fn emitBackslashes(self: &ArgIteratorWindows, buf: &Buffer, emit_count: usize) %void {
1469 fn emitBackslashes(self: &ArgIteratorWindows, buf: &Buffer, emit_count: usize) !void {
13831470 var i: usize = 0;
13841471 while (i < emit_count) : (i += 1) {
13851472 try buf.appendByte('\\');
......@@ -1409,16 +1496,20 @@ pub const ArgIteratorWindows = struct {
14091496};
14101497
14111498pub 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
14141503 pub fn init() ArgIterator {
14151504 return ArgIterator {
1416 .inner = if (builtin.os == Os.windows) ArgIteratorWindows.init() else ArgIteratorPosix.init(),
1505 .inner = InnerType.init(),
14171506 };
14181507 }
1508
1509 pub const NextError = ArgIteratorWindows.NextError;
14191510
14201511 /// 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) {
14221513 if (builtin.os == Os.windows) {
14231514 return self.inner.next(allocator);
14241515 } else {
......@@ -1443,7 +1534,7 @@ pub fn args() ArgIterator {
14431534}
14441535
14451536/// Caller must call freeArgs on result.
1446pub fn argsAlloc(allocator: &mem.Allocator) %[]const []u8 {
1537pub fn argsAlloc(allocator: &mem.Allocator) ![]const []u8 {
14471538 // TODO refactor to only make 1 allocation.
14481539 var it = args();
14491540 var contents = try Buffer.initSize(allocator, 0);
......@@ -1525,14 +1616,12 @@ test "std.os" {
15251616}
15261617
15271618
1528error Unexpected;
1529
15301619// TODO make this a build variable that you can set
15311620const unexpected_error_tracing = false;
15321621
15331622/// Call this when you made a syscall or something that sets errno
15341623/// and you get an unexpected error.
1535pub fn unexpectedErrorPosix(errno: usize) error {
1624pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {
15361625 if (unexpected_error_tracing) {
15371626 debug.warn("unexpected errno: {}\n", errno);
15381627 debug.dumpStackTrace();
......@@ -1542,7 +1631,7 @@ pub fn unexpectedErrorPosix(errno: usize) error {
15421631
15431632/// Call this when you made a windows DLL call or something that does SetLastError
15441633/// and you get an unexpected error.
1545pub fn unexpectedErrorWindows(err: windows.DWORD) error {
1634pub fn unexpectedErrorWindows(err: windows.DWORD) (error{Unexpected}) {
15461635 if (unexpected_error_tracing) {
15471636 debug.warn("unexpected GetLastError(): {}\n", err);
15481637 debug.dumpStackTrace();
......@@ -1550,7 +1639,7 @@ pub fn unexpectedErrorWindows(err: windows.DWORD) error {
15501639 return error.Unexpected;
15511640}
15521641
1553pub fn openSelfExe() %io.File {
1642pub fn openSelfExe() !io.File {
15541643 switch (builtin.os) {
15551644 Os.linux => {
15561645 return io.File.openRead("/proc/self/exe", null);
......@@ -1578,7 +1667,7 @@ test "openSelfExe" {
15781667/// This function may return an error if the current executable
15791668/// was deleted after spawning.
15801669/// Caller owns returned memory.
1581pub fn selfExePath(allocator: &mem.Allocator) %[]u8 {
1670pub fn selfExePath(allocator: &mem.Allocator) ![]u8 {
15821671 switch (builtin.os) {
15831672 Os.linux => {
15841673 // If the currently executing binary has been deleted,
......@@ -1621,7 +1710,7 @@ pub fn selfExePath(allocator: &mem.Allocator) %[]u8 {
16211710
16221711/// Get the directory path that contains the current executable.
16231712/// Caller owns returned memory.
1624pub fn selfExeDirPath(allocator: &mem.Allocator) %[]u8 {
1713pub fn selfExeDirPath(allocator: &mem.Allocator) ![]u8 {
16251714 switch (builtin.os) {
16261715 Os.linux => {
16271716 // 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:
720720// error SystemResources;
721721// error Io;
722722//
723// pub fn if_nametoindex(name: []u8) %u32 {
723// pub fn if_nametoindex(name: []u8) !u32 {
724724// var ifr: ifreq = undefined;
725725//
726726// if (name.len >= ifr.ifr_name.len) {
std/os/path.zig+11-18
......@@ -32,7 +32,7 @@ pub fn isSep(byte: u8) bool {
3232
3333/// Naively combines a series of paths with the native path seperator.
3434/// 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 {
3636 if (is_windows) {
3737 return joinWindows(allocator, paths);
3838 } else {
......@@ -40,11 +40,11 @@ pub fn join(allocator: &Allocator, paths: ...) %[]u8 {
4040 }
4141}
4242
43pub fn joinWindows(allocator: &Allocator, paths: ...) %[]u8 {
43pub fn joinWindows(allocator: &Allocator, paths: ...) ![]u8 {
4444 return mem.join(allocator, sep_windows, paths);
4545}
4646
47pub fn joinPosix(allocator: &Allocator, paths: ...) %[]u8 {
47pub fn joinPosix(allocator: &Allocator, paths: ...) ![]u8 {
4848 return mem.join(allocator, sep_posix, paths);
4949}
5050
......@@ -313,7 +313,7 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool {
313313}
314314
315315/// 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 {
317317 var paths: [args.len][]const u8 = undefined;
318318 comptime var arg_i = 0;
319319 inline while (arg_i < args.len) : (arg_i += 1) {
......@@ -323,7 +323,7 @@ pub fn resolve(allocator: &Allocator, args: ...) %[]u8 {
323323}
324324
325325/// 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 {
327327 if (is_windows) {
328328 return resolveWindows(allocator, paths);
329329 } else {
......@@ -337,7 +337,7 @@ pub fn resolveSlice(allocator: &Allocator, paths: []const []const u8) %[]u8 {
337337/// If all paths are relative it uses the current working directory as a starting point.
338338/// Each drive has its own current working directory.
339339/// 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 {
341341 if (paths.len == 0) {
342342 assert(is_windows); // resolveWindows called on non windows can't use getCwd
343343 return os.getCwd(allocator);
......@@ -520,7 +520,7 @@ pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) %[]u8 {
520520/// It resolves "." and "..".
521521/// The result does not have a trailing path separator.
522522/// 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 {
524524 if (paths.len == 0) {
525525 assert(!is_windows); // resolvePosix called on windows can't use getCwd
526526 return os.getCwd(allocator);
......@@ -890,7 +890,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) void {
890890/// resolve to the same path (after calling `resolve` on each), a zero-length
891891/// string is returned.
892892/// 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 {
894894 if (is_windows) {
895895 return relativeWindows(allocator, from, to);
896896 } else {
......@@ -898,7 +898,7 @@ pub fn relative(allocator: &Allocator, from: []const u8, to: []const u8) %[]u8 {
898898 }
899899}
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 {
902902 const resolved_from = try resolveWindows(allocator, [][]const u8{from});
903903 defer allocator.free(resolved_from);
904904
......@@ -971,7 +971,7 @@ pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8)
971971 return []u8{};
972972}
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 {
975975 const resolved_from = try resolvePosix(allocator, [][]const u8{from});
976976 defer allocator.free(resolved_from);
977977
......@@ -1066,18 +1066,11 @@ fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []cons
10661066 assert(mem.eql(u8, result, expected_output));
10671067}
10681068
1069error AccessDenied;
1070error FileNotFound;
1071error NotSupported;
1072error NotDir;
1073error NameTooLong;
1074error SymLinkLoop;
1075error InputOutput;
10761069/// Return the canonicalized absolute pathname.
10771070/// Expands all symbolic links and resolves references to `.`, `..`, and
10781071/// extra `/` characters in ::pathname.
10791072/// Caller must deallocate result.
1080pub fn real(allocator: &Allocator, pathname: []const u8) %[]u8 {
1073pub fn real(allocator: &Allocator, pathname: []const u8) ![]u8 {
10811074 switch (builtin.os) {
10821075 Os.windows => {
10831076 const pathname_buf = try allocator.alloc(u8, pathname.len + 1);
std/os/windows/util.zig+42-26
......@@ -1,4 +1,5 @@
11const std = @import("../../index.zig");
2const builtin = @import("builtin");
23const os = std.os;
34const windows = std.os.windows;
45const assert = std.debug.assert;
......@@ -6,11 +7,13 @@ const mem = std.mem;
67const BufMap = std.BufMap;
78const cstr = std.cstr;
89
9error WaitAbandoned;
10error WaitTimeOut;
11error Unexpected;
10pub const WaitError = error {
11 WaitAbandoned,
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 {
1417 const result = windows.WaitForSingleObject(handle, milliseconds);
1518 return switch (result) {
1619 windows.WAIT_ABANDONED => error.WaitAbandoned,
......@@ -30,21 +33,24 @@ pub fn windowsClose(handle: windows.HANDLE) void {
3033 assert(windows.CloseHandle(handle) != 0);
3134}
3235
33error SystemResources;
34error OperationAborted;
35error IoPending;
36error BrokenPipe;
36pub const WriteError = error {
37 SystemResources,
38 OperationAborted,
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 {
3945 if (windows.WriteFile(handle, @ptrCast(&const c_void, bytes.ptr), u32(bytes.len), null, null) == 0) {
4046 const err = windows.GetLastError();
4147 return switch (err) {
42 windows.ERROR.INVALID_USER_BUFFER => error.SystemResources,
43 windows.ERROR.NOT_ENOUGH_MEMORY => error.SystemResources,
44 windows.ERROR.OPERATION_ABORTED => error.OperationAborted,
45 windows.ERROR.NOT_ENOUGH_QUOTA => error.SystemResources,
46 windows.ERROR.IO_PENDING => error.IoPending,
47 windows.ERROR.BROKEN_PIPE => error.BrokenPipe,
48 windows.ERROR.INVALID_USER_BUFFER => WriteError.SystemResources,
49 windows.ERROR.NOT_ENOUGH_MEMORY => WriteError.SystemResources,
50 windows.ERROR.OPERATION_ABORTED => WriteError.OperationAborted,
51 windows.ERROR.NOT_ENOUGH_QUOTA => WriteError.SystemResources,
52 windows.ERROR.IO_PENDING => WriteError.IoPending,
53 windows.ERROR.BROKEN_PIPE => WriteError.BrokenPipe,
4854 else => os.unexpectedErrorWindows(err),
4955 };
5056 }
......@@ -75,15 +81,24 @@ pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool {
7581 mem.indexOf(u16, name_wide, []u16{'-','p','t','y'}) != null;
7682}
7783
78error SharingViolation;
79error PipeBusy;
84pub const OpenError = error {
85 SharingViolation,
86 PathAlreadyExists,
87 FileNotFound,
88 AccessDenied,
89 PipeBusy,
90 Unexpected,
91 OutOfMemory,
92 NameTooLong,
93};
8094
8195/// `file_path` may need to be copied in memory to add a null terminating byte. In this case
8296/// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed
8397/// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned.
8498/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
8599pub 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.HANDLE
100 creation_disposition: windows.DWORD, flags_and_attrs: windows.DWORD, allocator: ?&mem.Allocator)
101 OpenError!windows.HANDLE
87102{
88103 var stack_buf: [os.max_noalloc_path_len]u8 = undefined;
89104 var path0: []u8 = undefined;
......@@ -107,11 +122,11 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m
107122 if (result == windows.INVALID_HANDLE_VALUE) {
108123 const err = windows.GetLastError();
109124 return switch (err) {
110 windows.ERROR.SHARING_VIOLATION => error.SharingViolation,
111 windows.ERROR.ALREADY_EXISTS, windows.ERROR.FILE_EXISTS => error.PathAlreadyExists,
112 windows.ERROR.FILE_NOT_FOUND => error.FileNotFound,
113 windows.ERROR.ACCESS_DENIED => error.AccessDenied,
114 windows.ERROR.PIPE_BUSY => error.PipeBusy,
125 windows.ERROR.SHARING_VIOLATION => OpenError.SharingViolation,
126 windows.ERROR.ALREADY_EXISTS, windows.ERROR.FILE_EXISTS => OpenError.PathAlreadyExists,
127 windows.ERROR.FILE_NOT_FOUND => OpenError.FileNotFound,
128 windows.ERROR.ACCESS_DENIED => OpenError.AccessDenied,
129 windows.ERROR.PIPE_BUSY => OpenError.PipeBusy,
115130 else => os.unexpectedErrorWindows(err),
116131 };
117132 }
......@@ -120,7 +135,7 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m
120135}
121136
122137/// 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 {
124139 // count bytes needed
125140 const bytes_needed = x: {
126141 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)
151166 return result;
152167}
153168
154error DllNotFound;
155pub fn windowsLoadDll(allocator: &mem.Allocator, dll_path: []const u8) %windows.HMODULE {
169pub fn windowsLoadDll(allocator: &mem.Allocator, dll_path: []const u8) !windows.HMODULE {
156170 const padded_buff = try cstr.addNullByte(allocator, dll_path);
157171 defer allocator.free(padded_buff);
158172 return windows.LoadLibraryA(padded_buff.ptr) ?? error.DllNotFound;
......@@ -164,6 +178,8 @@ pub fn windowsUnloadDll(hModule: windows.HMODULE) void {
164178
165179
166180test "InvalidDll" {
181 if (builtin.os != builtin.Os.windows) return;
182
167183 const DllName = "asdf.dll";
168184 const allocator = std.debug.global_allocator;
169185 const handle = os.windowsLoadDll(allocator, DllName) catch |err| {
std/special/bootstrap.zig+2-2
......@@ -77,7 +77,7 @@ fn callMain() u8 {
7777 },
7878 builtin.TypeId.Int => {
7979 if (@typeOf(root.main).ReturnType.bit_count != 8) {
80 @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '%void'");
80 @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'");
8181 }
8282 return root.main();
8383 },
......@@ -91,6 +91,6 @@ fn callMain() u8 {
9191 };
9292 return 0;
9393 },
94 else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '%void'"),
94 else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"),
9595 }
9696}
std/special/build_file_template.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) %void {
3pub fn build(b: &Builder) !void {
44 const mode = b.standardReleaseOptions();
55 const exe = b.addExecutable("YOUR_NAME_HERE", "src/main.zig");
66 exe.setBuildMode(mode);
std/special/build_runner.zig+19-10
......@@ -1,5 +1,6 @@
11const root = @import("@build");
22const std = @import("std");
3const builtin = @import("builtin");
34const io = std.io;
45const fmt = std.fmt;
56const os = std.os;
......@@ -8,9 +9,7 @@ const mem = std.mem;
89const ArrayList = std.ArrayList;
910const warn = std.debug.warn;
1011
11error InvalidArgs;
12
13pub fn main() %void {
12pub fn main() !void {
1413 var arg_it = os.args();
1514
1615 // TODO use a more general purpose allocator here
......@@ -45,14 +44,14 @@ pub fn main() %void {
4544
4645 var stderr_file = io.getStdErr();
4746 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: {
4948 stderr_file_stream = io.FileOutStream.init(f);
5049 break :x &stderr_file_stream.stream;
5150 } else |err| err;
5251
5352 var stdout_file = io.getStdOut();
5453 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: {
5655 stdout_file_stream = io.FileOutStream.init(f);
5756 break :x &stdout_file_stream.stream;
5857 } else |err| err;
......@@ -112,7 +111,7 @@ pub fn main() %void {
112111 }
113112
114113 builder.setInstallPrefix(prefix);
115 try root.build(&builder);
114 try runBuild(&builder);
116115
117116 if (builder.validateUserInputDidItFail())
118117 return usageAndErr(&builder, true, try stderr_stream);
......@@ -125,11 +124,19 @@ pub fn main() %void {
125124 };
126125}
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 {
129136 // run the build script to collect the options
130137 if (!already_ran_build) {
131138 builder.setInstallPrefix(null);
132 try root.build(builder);
139 try runBuild(builder);
133140 }
134141
135142 // 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)
184191 );
185192}
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 {
188195 usage(builder, already_ran_build, out_stream) catch {};
189196 return error.InvalidArgs;
190197}
191198
192fn unwrapArg(arg: %[]u8) %[]u8 {
199const UnwrapArgError = error {OutOfMemory};
200
201fn unwrapArg(arg: UnwrapArgError![]u8) UnwrapArgError![]u8 {
193202 return arg catch |err| {
194203 warn("Unable to parse command line: {}\n", err);
195204 return err;
std/special/test_runner.zig+1-1
......@@ -4,7 +4,7 @@ const builtin = @import("builtin");
44const test_fn_list = builtin.__zig_test_fn_slice;
55const warn = std.debug.warn;
66
7pub fn main() %void {
7pub fn main() !void {
88 for (test_fn_list) |test_fn, i| {
99 warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name);
1010
std/unicode.zig+6-14
......@@ -1,11 +1,9 @@
11const std = @import("./index.zig");
22
3error Utf8InvalidStartByte;
4
53/// Given the first byte of a UTF-8 codepoint,
64/// returns a number 1-4 indicating the total length of the codepoint in bytes.
75/// 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 {
97 if (first_byte < 0b10000000) return u3(1);
108 if (first_byte & 0b11100000 == 0b11000000) return u3(2);
119 if (first_byte & 0b11110000 == 0b11100000) return u3(3);
......@@ -13,16 +11,11 @@ pub fn utf8ByteSequenceLength(first_byte: u8) %u3 {
1311 return error.Utf8InvalidStartByte;
1412}
1513
16error Utf8OverlongEncoding;
17error Utf8ExpectedContinuation;
18error Utf8EncodesSurrogateHalf;
19error Utf8CodepointTooLarge;
20
2114/// Decodes the UTF-8 codepoint encoded in the given slice of bytes.
2215/// bytes.len must be equal to utf8ByteSequenceLength(bytes[0]) catch unreachable.
2316/// If you already know the length at comptime, you can call one of
2417/// utf8Decode2,utf8Decode3,utf8Decode4 directly instead of this function.
25pub fn utf8Decode(bytes: []const u8) %u32 {
18pub fn utf8Decode(bytes: []const u8) !u32 {
2619 return switch (bytes.len) {
2720 1 => u32(bytes[0]),
2821 2 => utf8Decode2(bytes),
......@@ -31,7 +24,7 @@ pub fn utf8Decode(bytes: []const u8) %u32 {
3124 else => unreachable,
3225 };
3326}
34pub fn utf8Decode2(bytes: []const u8) %u32 {
27pub fn utf8Decode2(bytes: []const u8) !u32 {
3528 std.debug.assert(bytes.len == 2);
3629 std.debug.assert(bytes[0] & 0b11100000 == 0b11000000);
3730 var value: u32 = bytes[0] & 0b00011111;
......@@ -44,7 +37,7 @@ pub fn utf8Decode2(bytes: []const u8) %u32 {
4437
4538 return value;
4639}
47pub fn utf8Decode3(bytes: []const u8) %u32 {
40pub fn utf8Decode3(bytes: []const u8) !u32 {
4841 std.debug.assert(bytes.len == 3);
4942 std.debug.assert(bytes[0] & 0b11110000 == 0b11100000);
5043 var value: u32 = bytes[0] & 0b00001111;
......@@ -62,7 +55,7 @@ pub fn utf8Decode3(bytes: []const u8) %u32 {
6255
6356 return value;
6457}
65pub fn utf8Decode4(bytes: []const u8) %u32 {
58pub fn utf8Decode4(bytes: []const u8) !u32 {
6659 std.debug.assert(bytes.len == 4);
6760 std.debug.assert(bytes[0] & 0b11111000 == 0b11110000);
6861 var value: u32 = bytes[0] & 0b00000111;
......@@ -85,7 +78,6 @@ pub fn utf8Decode4(bytes: []const u8) %u32 {
8578 return value;
8679}
8780
88error UnexpectedEof;
8981test "valid utf8" {
9082 testValid("\x00", 0x0);
9183 testValid("\x20", 0x20);
......@@ -161,7 +153,7 @@ fn testValid(bytes: []const u8, expected_codepoint: u32) void {
161153 std.debug.assert((testDecode(bytes) catch unreachable) == expected_codepoint);
162154}
163155
164fn testDecode(bytes: []const u8) %u32 {
156fn testDecode(bytes: []const u8) !u32 {
165157 const length = try utf8ByteSequenceLength(bytes[0]);
166158 if (bytes.len < length) return error.UnexpectedEof;
167159 std.debug.assert(bytes.len == length);
test/cases/cast.zig+16-18
......@@ -32,7 +32,6 @@ fn funcWithConstPtrPtr(x: &const &i32) void {
3232 **x += 1;
3333}
3434
35error ItBroke;
3635test "explicit cast from integer to error type" {
3736 testCastIntToErr(error.ItBroke);
3837 comptime testCastIntToErr(error.ItBroke);
......@@ -75,7 +74,7 @@ test "string literal to &const []const u8" {
7574 assert(mem.eql(u8, *x, "hello"));
7675}
7776
78test "implicitly cast from T to %?T" {
77test "implicitly cast from T to error!?T" {
7978 castToMaybeTypeError(1);
8079 comptime castToMaybeTypeError(1);
8180}
......@@ -84,37 +83,37 @@ const A = struct {
8483};
8584fn castToMaybeTypeError(z: i32) void {
8685 const x = i32(1);
87 const y: %?i32 = x;
86 const y: error!?i32 = x;
8887 assert(??(try y) == 1);
8988
9089 const f = z;
91 const g: %?i32 = f;
90 const g: error!?i32 = f;
9291
9392 const a = A{ .a = z };
94 const b: %?A = a;
93 const b: error!?A = a;
9594 assert((??(b catch unreachable)).a == 1);
9695}
9796
98test "implicitly cast from int to %?T" {
97test "implicitly cast from int to error!?T" {
9998 implicitIntLitToMaybe();
10099 comptime implicitIntLitToMaybe();
101100}
102101fn implicitIntLitToMaybe() void {
103102 const f: ?i32 = 1;
104 const g: %?i32 = 1;
103 const g: error!?i32 = 1;
105104}
106105
107106
108test "return null from fn() %?&T" {
107test "return null from fn() error!?&T" {
109108 const a = returnNullFromMaybeTypeErrorRef();
110109 const b = returnNullLitFromMaybeTypeErrorRef();
111110 assert((try a) == null and (try b) == null);
112111}
113fn returnNullFromMaybeTypeErrorRef() %?&A {
112fn returnNullFromMaybeTypeErrorRef() error!?&A {
114113 const a: ?&A = null;
115114 return a;
116115}
117fn returnNullLitFromMaybeTypeErrorRef() %?&A {
116fn returnNullLitFromMaybeTypeErrorRef() error!?&A {
118117 return null;
119118}
120119
......@@ -161,7 +160,7 @@ fn castToMaybeSlice() ?[]const u8 {
161160}
162161
163162
164test "implicitly cast from [0]T to %[]T" {
163test "implicitly cast from [0]T to error![]T" {
165164 testCastZeroArrayToErrSliceMut();
166165 comptime testCastZeroArrayToErrSliceMut();
167166}
......@@ -170,11 +169,11 @@ fn testCastZeroArrayToErrSliceMut() void {
170169 assert((gimmeErrOrSlice() catch unreachable).len == 0);
171170}
172171
173fn gimmeErrOrSlice() %[]u8 {
172fn gimmeErrOrSlice() error![]u8 {
174173 return []u8{};
175174}
176175
177test "peer type resolution: [0]u8, []const u8, and %[]u8" {
176test "peer type resolution: [0]u8, []const u8, and error![]u8" {
178177 {
179178 var data = "hi";
180179 const slice = data[0..];
......@@ -188,7 +187,7 @@ test "peer type resolution: [0]u8, []const u8, and %[]u8" {
188187 assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
189188 }
190189}
191fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) %[]u8 {
190fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) error![]u8 {
192191 if (a) {
193192 return []u8{};
194193 }
......@@ -230,7 +229,7 @@ fn foo(args: ...) void {
230229
231230
232231test "peer type resolution: error and [N]T" {
233 // TODO: implicit %T to %U where T can implicitly cast to U
232 // TODO: implicit error!T to error!U where T can implicitly cast to U
234233 //assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
235234 //comptime assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
236235
......@@ -238,14 +237,13 @@ test "peer type resolution: error and [N]T" {
238237 comptime assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
239238}
240239
241error BadValue;
242//fn testPeerErrorAndArray(x: u8) %[]const u8 {
240//fn testPeerErrorAndArray(x: u8) error![]const u8 {
243241// return switch (x) {
244242// 0x00 => "OK",
245243// else => error.BadValue,
246244// };
247245//}
248fn testPeerErrorAndArray2(x: u8) %[]const u8 {
246fn testPeerErrorAndArray2(x: u8) error![]const u8 {
249247 return switch (x) {
250248 0x00 => "OK",
251249 0x01 => "OKK",
test/cases/defer.zig+1-3
......@@ -3,9 +3,7 @@ const assert = @import("std").debug.assert;
33var result: [3]u8 = undefined;
44var index: usize = undefined;
55
6error FalseNotAllowed;
7
8fn runSomeErrorDefers(x: bool) %bool {
6fn runSomeErrorDefers(x: bool) !bool {
97 index = 0;
108 defer {result[index] = 'a'; index += 1;}
119 errdefer {result[index] = 'b'; index += 1;}
test/cases/enum_with_members.zig+1-1
......@@ -6,7 +6,7 @@ const ET = union(enum) {
66 SINT: i32,
77 UINT: u32,
88
9 pub fn print(a: &const ET, buf: []u8) %usize {
9 pub fn print(a: &const ET, buf: []u8) error!usize {
1010 return switch (*a) {
1111 ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
1212 ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
test/cases/error.zig+85-18
......@@ -1,16 +1,18 @@
1const assert = @import("std").debug.assert;
2const mem = @import("std").mem;
1const std = @import("std");
2const assert = std.debug.assert;
3const mem = std.mem;
4const builtin = @import("builtin");
35
4pub fn foo() %i32 {
6pub fn foo() error!i32 {
57 const x = try bar();
68 return x + 1;
79}
810
9pub fn bar() %i32 {
11pub fn bar() error!i32 {
1012 return 13;
1113}
1214
13pub fn baz() %i32 {
15pub fn baz() error!i32 {
1416 const y = foo() catch 1234;
1517 return y + 1;
1618}
......@@ -19,7 +21,6 @@ test "error wrapping" {
1921 assert((baz() catch unreachable) == 15);
2022}
2123
22error ItBroke;
2324fn gimmeItBroke() []const u8 {
2425 return @errorName(error.ItBroke);
2526}
......@@ -28,8 +29,6 @@ test "@errorName" {
2829 assert(mem.eql(u8, @errorName(error.AnError), "AnError"));
2930 assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
3031}
31error AnError;
32error ALongerErrorName;
3332
3433
3534test "error values" {
......@@ -37,16 +36,11 @@ test "error values" {
3736 const b = i32(error.err2);
3837 assert(a != b);
3938}
40error err1;
41error err2;
4239
4340
4441test "redefinition of error values allowed" {
4542 shouldBeNotEqual(error.AnError, error.SecondError);
4643}
47error AnError;
48error AnError;
49error SecondError;
5044fn shouldBeNotEqual(a: error, b: error) void {
5145 if (a == b) unreachable;
5246}
......@@ -58,8 +52,7 @@ test "error binary operator" {
5852 assert(a == 3);
5953 assert(b == 10);
6054}
61error ItBroke;
62fn errBinaryOperatorG(x: bool) %isize {
55fn errBinaryOperatorG(x: bool) error!isize {
6356 return if (x) error.ItBroke else isize(10);
6457}
6558
......@@ -68,18 +61,92 @@ test "unwrap simple value from error" {
6861 const i = unwrapSimpleValueFromErrorDo() catch unreachable;
6962 assert(i == 13);
7063}
71fn unwrapSimpleValueFromErrorDo() %isize { return 13; }
64fn unwrapSimpleValueFromErrorDo() error!isize { return 13; }
7265
7366
7467test "error return in assignment" {
7568 doErrReturnInAssignment() catch unreachable;
7669}
7770
78fn doErrReturnInAssignment() %void {
71fn doErrReturnInAssignment() error!void {
7972 var x : i32 = undefined;
8073 x = try makeANonErr();
8174}
8275
83fn makeANonErr() %i32 {
76fn makeANonErr() error!i32 {
8477 return 1;
8578}
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 @@
11const assert = @import("std").debug.assert;
22
3fn foo(id: u64) %i32 {
3fn foo(id: u64) !i32 {
44 return switch (id) {
55 1 => getErrInt(),
66 2 => {
......@@ -11,9 +11,7 @@ fn foo(id: u64) %i32 {
1111 };
1212}
1313
14fn getErrInt() %i32 { return 0; }
15
16error ItBroke;
14fn getErrInt() error!i32 { return 0; }
1715
1816test "ir block deps" {
1917 assert((foo(1) catch unreachable) == 0);
test/cases/misc.zig+4-4
......@@ -262,7 +262,7 @@ test "generic malloc free" {
262262 memFree(u8, a);
263263}
264264const some_mem : [100]u8 = undefined;
265fn memAlloc(comptime T: type, n: usize) %[]T {
265fn memAlloc(comptime T: type, n: usize) error![]T {
266266 return @ptrCast(&T, &some_mem[0])[0..n];
267267}
268268fn memFree(comptime T: type, memory: []T) void { }
......@@ -419,7 +419,7 @@ test "cast slice to u8 slice" {
419419test "pointer to void return type" {
420420 testPointerToVoidReturnType() catch unreachable;
421421}
422fn testPointerToVoidReturnType() %void {
422fn testPointerToVoidReturnType() error!void {
423423 const a = testPointerToVoidReturnType2();
424424 return *a;
425425}
......@@ -475,8 +475,8 @@ test "@typeId" {
475475 assert(@typeId(@typeOf(undefined)) == Tid.UndefinedLiteral);
476476 assert(@typeId(@typeOf(null)) == Tid.NullLiteral);
477477 assert(@typeId(?i32) == Tid.Nullable);
478 assert(@typeId(%i32) == Tid.ErrorUnion);
479 assert(@typeId(error) == Tid.Error);
478 assert(@typeId(error!i32) == Tid.ErrorUnion);
479 assert(@typeId(error) == Tid.ErrorSet);
480480 assert(@typeId(AnEnum) == Tid.Enum);
481481 assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
482482 assert(@typeId(AUnionEnum) == Tid.Union);
test/cases/reflection.zig+1-1
......@@ -5,7 +5,7 @@ test "reflection: array, pointer, nullable, error union type child" {
55 comptime {
66 assert(([10]u8).Child == u8);
77 assert((&u8).Child == u8);
8 assert((%u8).Child == u8);
8 assert((error!u8).Payload == u8);
99 assert((?u8).Child == u8);
1010 }
1111}
test/cases/switch.zig+1-1
......@@ -225,7 +225,7 @@ fn switchWithUnreachable(x: i32) i32 {
225225 return 10;
226226}
227227
228fn return_a_number() %i32 {
228fn return_a_number() error!i32 {
229229 return 1;
230230}
231231
test/cases/switch_prong_err_enum.zig+2-4
......@@ -2,19 +2,17 @@ const assert = @import("std").debug.assert;
22
33var read_count: u64 = 0;
44
5fn readOnce() %u64 {
5fn readOnce() error!u64 {
66 read_count += 1;
77 return read_count;
88}
99
10error InvalidDebugInfo;
11
1210const FormValue = union(enum) {
1311 Address: u64,
1412 Other: bool,
1513};
1614
17fn doThing(form_id: u64) %FormValue {
15fn doThing(form_id: u64) error!FormValue {
1816 return switch (form_id) {
1917 17 => FormValue { .Address = try readOnce() },
2018 else => error.InvalidDebugInfo,
test/cases/switch_prong_implicit_cast.zig+1-3
......@@ -5,9 +5,7 @@ const FormValue = union(enum) {
55 Two: bool,
66};
77
8error Whatever;
9
10fn foo(id: u64) %FormValue {
8fn foo(id: u64) !FormValue {
119 return switch (id) {
1210 2 => FormValue { .Two = true },
1311 1 => FormValue { .One = {} },
test/cases/try.zig+2-5
......@@ -17,10 +17,7 @@ fn tryOnErrorUnionImpl() void {
1717 assert(x == 11);
1818}
1919
20error ItBroke;
21error NoMem;
22error CrappedOut;
23fn returnsTen() %i32 {
20fn returnsTen() error!i32 {
2421 return 10;
2522}
2623
......@@ -32,7 +29,7 @@ test "try without vars" {
3229 assert(result2 == 1);
3330}
3431
35fn failIfTrue(ok: bool) %void {
32fn failIfTrue(ok: bool) error!void {
3633 if (ok) {
3734 return error.ItBroke;
3835 } else {
test/cases/union.zig+1-1
......@@ -13,7 +13,7 @@ const Agg = struct {
1313const v1 = Value { .Int = 1234 };
1414const v2 = Value { .Array = []u8{3} ** 9 };
1515
16const err = (%Agg)(Agg {
16const err = (error!Agg)(Agg {
1717 .val1 = v1,
1818 .val2 = v2,
1919});
test/cases/while.zig+4-6
......@@ -50,7 +50,7 @@ fn runContinueAndBreakTest() void {
5050test "return with implicit cast from while loop" {
5151 returnWithImplicitCastFromWhileLoopTest() catch unreachable;
5252}
53fn returnWithImplicitCastFromWhileLoopTest() %void {
53fn returnWithImplicitCastFromWhileLoopTest() error!void {
5454 while (true) {
5555 return;
5656 }
......@@ -116,8 +116,7 @@ test "while with error union condition" {
116116}
117117
118118var numbers_left: i32 = undefined;
119error OutOfNumbers;
120fn getNumberOrErr() %i32 {
119fn getNumberOrErr() error!i32 {
121120 return if (numbers_left == 0)
122121 error.OutOfNumbers
123122 else x: {
......@@ -205,8 +204,7 @@ fn testContinueOuter() void {
205204
206205fn returnNull() ?i32 { return null; }
207206fn returnMaybe(x: i32) ?i32 { return x; }
208error YouWantedAnError;
209fn returnError() %i32 { return error.YouWantedAnError; }
210fn returnSuccess(x: i32) %i32 { return x; }
207fn returnError() error!i32 { return error.YouWantedAnError; }
208fn returnSuccess(x: i32) error!i32 { return x; }
211209fn returnFalse() bool { return false; }
212210fn returnTrue() bool { return true; }
test/compare_output.zig+17-18
......@@ -15,7 +15,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
1515 \\use @import("std").io;
1616 \\use @import("foo.zig");
1717 \\
18 \\pub fn main() %void {
18 \\pub fn main() void {
1919 \\ privateFunction();
2020 \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);
2121 \\ stdout.print("OK 2\n") catch unreachable;
......@@ -49,7 +49,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
4949 \\use @import("foo.zig");
5050 \\use @import("bar.zig");
5151 \\
52 \\pub fn main() %void {
52 \\pub fn main() void {
5353 \\ foo_function();
5454 \\ bar_function();
5555 \\}
......@@ -89,7 +89,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
8989 var tc = cases.create("two files use import each other",
9090 \\use @import("a.zig");
9191 \\
92 \\pub fn main() %void {
92 \\pub fn main() void {
9393 \\ ok();
9494 \\}
9595 , "OK\n");
......@@ -118,7 +118,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
118118 cases.add("hello world without libc",
119119 \\const io = @import("std").io;
120120 \\
121 \\pub fn main() %void {
121 \\pub fn main() void {
122122 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
123123 \\ stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;
124124 \\}
......@@ -268,7 +268,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
268268 \\const z = io.stdin_fileno;
269269 \\const x : @typeOf(y) = 1234;
270270 \\const y : u16 = 5678;
271 \\pub fn main() %void {
271 \\pub fn main() void {
272272 \\ var x_local : i32 = print_ok(x);
273273 \\}
274274 \\fn print_ok(val: @typeOf(x)) @typeOf(foo) {
......@@ -351,7 +351,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
351351 \\ fn method(b: &const Bar) bool { return true; }
352352 \\};
353353 \\
354 \\pub fn main() %void {
354 \\pub fn main() void {
355355 \\ const bar = Bar {.field2 = 13,};
356356 \\ const foo = Foo {.field1 = bar,};
357357 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
......@@ -367,7 +367,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
367367
368368 cases.add("defer with only fallthrough",
369369 \\const io = @import("std").io;
370 \\pub fn main() %void {
370 \\pub fn main() void {
371371 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
372372 \\ stdout.print("before\n") catch unreachable;
373373 \\ defer stdout.print("defer1\n") catch unreachable;
......@@ -380,7 +380,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
380380 cases.add("defer with return",
381381 \\const io = @import("std").io;
382382 \\const os = @import("std").os;
383 \\pub fn main() %void {
383 \\pub fn main() void {
384384 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
385385 \\ stdout.print("before\n") catch unreachable;
386386 \\ defer stdout.print("defer1\n") catch unreachable;
......@@ -394,10 +394,10 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
394394
395395 cases.add("errdefer and it fails",
396396 \\const io = @import("std").io;
397 \\pub fn main() %void {
397 \\pub fn main() void {
398398 \\ do_test() catch return;
399399 \\}
400 \\fn do_test() %void {
400 \\fn do_test() !void {
401401 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
402402 \\ stdout.print("before\n") catch unreachable;
403403 \\ defer stdout.print("defer1\n") catch unreachable;
......@@ -406,18 +406,17 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
406406 \\ defer stdout.print("defer3\n") catch unreachable;
407407 \\ stdout.print("after\n") catch unreachable;
408408 \\}
409 \\error IToldYouItWouldFail;
410 \\fn its_gonna_fail() %void {
409 \\fn its_gonna_fail() !void {
411410 \\ return error.IToldYouItWouldFail;
412411 \\}
413412 , "before\ndeferErr\ndefer1\n");
414413
415414 cases.add("errdefer and it passes",
416415 \\const io = @import("std").io;
417 \\pub fn main() %void {
416 \\pub fn main() void {
418417 \\ do_test() catch return;
419418 \\}
420 \\fn do_test() %void {
419 \\fn do_test() !void {
421420 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
422421 \\ stdout.print("before\n") catch unreachable;
423422 \\ defer stdout.print("defer1\n") catch unreachable;
......@@ -426,7 +425,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
426425 \\ defer stdout.print("defer3\n") catch unreachable;
427426 \\ stdout.print("after\n") catch unreachable;
428427 \\}
429 \\fn its_gonna_pass() %void { }
428 \\fn its_gonna_pass() error!void { }
430429 , "before\nafter\ndefer3\ndefer1\n");
431430
432431 cases.addCase(x: {
......@@ -434,7 +433,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
434433 \\const foo_txt = @embedFile("foo.txt");
435434 \\const io = @import("std").io;
436435 \\
437 \\pub fn main() %void {
436 \\pub fn main() void {
438437 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
439438 \\ stdout.print(foo_txt) catch unreachable;
440439 \\}
......@@ -452,7 +451,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
452451 \\const os = std.os;
453452 \\const allocator = std.debug.global_allocator;
454453 \\
455 \\pub fn main() %void {
454 \\pub fn main() !void {
456455 \\ var args_it = os.args();
457456 \\ var stdout_file = try io.getStdOut();
458457 \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);
......@@ -493,7 +492,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
493492 \\const os = std.os;
494493 \\const allocator = std.debug.global_allocator;
495494 \\
496 \\pub fn main() %void {
495 \\pub fn main() !void {
497496 \\ var args_it = os.args();
498497 \\ var stdout_file = try io.getStdOut();
499498 \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);
test/compile_errors.zig+219-18
......@@ -1,6 +1,208 @@
11const tests = @import("tests.zig");
22
33pub 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
4206 cases.add("cast negative integer literal to usize",
5207 \\export fn entry() void {
6208 \\ const x = usize(-10);
......@@ -112,12 +314,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
112314
113315 cases.add("wrong return type for main",
114316 \\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
117319 cases.add("double ?? on main return value",
118320 \\pub fn main() ??void {
119321 \\}
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
122324 cases.add("bad identifier in function with struct defined inside function which references local const",
123325 \\export fn entry() void {
......@@ -1173,7 +1375,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
11731375 \\export fn f() void {
11741376 \\ try something();
11751377 \\}
1176 \\fn something() %void { }
1378 \\fn something() error!void { }
11771379 ,
11781380 ".tmp_source.zig:2:5: error: expected type 'void', found 'error'");
11791381
......@@ -1264,7 +1466,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
12641466 , ".tmp_source.zig:3:11: error: cannot assign to constant");
12651467
12661468 cases.add("main function with bogus args type",
1267 \\pub fn main(args: [][]bogus) %void {}
1469 \\pub fn main(args: [][]bogus) !void {}
12681470 , ".tmp_source.zig:1:23: error: use of undeclared identifier 'bogus'");
12691471
12701472 cases.add("for loop missing element param",
......@@ -1396,7 +1598,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
13961598 , ".tmp_source.zig:6:13: error: cannot assign to constant");
13971599
13981600 cases.add("return from defer expression",
1399 \\pub fn testTrickyDefer() %void {
1601 \\pub fn testTrickyDefer() !void {
14001602 \\ defer canFail() catch {};
14011603 \\
14021604 \\ defer try canFail();
......@@ -1404,7 +1606,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
14041606 \\ const a = maybeInt() ?? return;
14051607 \\}
14061608 \\
1407 \\fn canFail() %void { }
1609 \\fn canFail() error!void { }
14081610 \\
14091611 \\pub fn maybeInt() ?i32 {
14101612 \\ return 0;
......@@ -1534,7 +1736,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
15341736 \\export fn foo() void {
15351737 \\ bar() catch unreachable;
15361738 \\}
1537 \\fn bar() %i32 { return 0; }
1739 \\fn bar() error!i32 { return 0; }
15381740 , ".tmp_source.zig:2:11: error: expression value is ignored");
15391741
15401742 cases.add("ignored statement value",
......@@ -1565,7 +1767,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
15651767 \\export fn foo() void {
15661768 \\ defer bar();
15671769 \\}
1568 \\fn bar() %i32 { return 0; }
1770 \\fn bar() error!i32 { return 0; }
15691771 , ".tmp_source.zig:2:14: error: expression value is ignored");
15701772
15711773 cases.add("dereference an array",
......@@ -1632,13 +1834,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
16321834 , ".tmp_source.zig:2:21: error: expected pointer, found 'usize'");
16331835
16341836 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;
1636 \\const u2 = @IntType(false, 2);
1637 \\fn foo(e: error) u2 {
1837 \\const Error = error { A, B, C, D, E, F, G, H };
1838 \\fn foo(e: Error) u2 {
16381839 \\ return u2(e);
16391840 \\}
16401841 \\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
16431844 cases.add("asm at compile time",
16441845 \\comptime {
......@@ -1821,9 +2022,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
18212022 \\export fn foo() void {
18222023 \\ while (bar()) {}
18232024 \\}
1824 \\fn bar() %i32 { return 1; }
2025 \\fn bar() error!i32 { return 1; }
18252026 ,
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
18282029 cases.add("while expected nullable, got bool",
18292030 \\export fn foo() void {
......@@ -1837,9 +2038,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
18372038 \\export fn foo() void {
18382039 \\ while (bar()) |x| {}
18392040 \\}
1840 \\fn bar() %i32 { return 1; }
2041 \\fn bar() error!i32 { return 1; }
18412042 ,
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
18442045 cases.add("while expected error union, got bool",
18452046 \\export fn foo() void {
......@@ -1983,7 +2184,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
19832184 \\fn foo1(args: ...) void {}
19842185 \\fn foo2(args: ...) void {}
19852186 \\
1986 \\pub fn main() %void {
2187 \\pub fn main() !void {
19872188 \\ foos[0]();
19882189 \\}
19892190 ,
......@@ -1995,7 +2196,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
19952196 \\fn foo1(arg: var) void {}
19962197 \\fn foo2(arg: var) void {}
19972198 \\
1998 \\pub fn main() %void {
2199 \\pub fn main() !void {
19992200 \\ foos[0](true);
20002201 \\}
20012202 ,
test/runtime_safety.zig+36-38
......@@ -5,7 +5,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
55 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
66 \\ @import("std").os.exit(126);
77 \\}
8 \\pub fn main() %void {
8 \\pub fn main() void {
99 \\ @panic("oh no");
1010 \\}
1111 );
......@@ -14,7 +14,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
1414 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
1515 \\ @import("std").os.exit(126);
1616 \\}
17 \\pub fn main() %void {
17 \\pub fn main() void {
1818 \\ const a = []i32{1, 2, 3, 4};
1919 \\ baz(bar(a));
2020 \\}
......@@ -28,8 +28,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
2828 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
2929 \\ @import("std").os.exit(126);
3030 \\}
31 \\error Whatever;
32 \\pub fn main() %void {
31 \\pub fn main() !void {
3332 \\ const x = add(65530, 10);
3433 \\ if (x == 0) return error.Whatever;
3534 \\}
......@@ -42,8 +41,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
4241 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
4342 \\ @import("std").os.exit(126);
4443 \\}
45 \\error Whatever;
46 \\pub fn main() %void {
44 \\pub fn main() !void {
4745 \\ const x = sub(10, 20);
4846 \\ if (x == 0) return error.Whatever;
4947 \\}
......@@ -56,8 +54,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
5654 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
5755 \\ @import("std").os.exit(126);
5856 \\}
59 \\error Whatever;
60 \\pub fn main() %void {
57 \\pub fn main() !void {
6158 \\ const x = mul(300, 6000);
6259 \\ if (x == 0) return error.Whatever;
6360 \\}
......@@ -70,8 +67,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
7067 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
7168 \\ @import("std").os.exit(126);
7269 \\}
73 \\error Whatever;
74 \\pub fn main() %void {
70 \\pub fn main() !void {
7571 \\ const x = neg(-32768);
7672 \\ if (x == 32767) return error.Whatever;
7773 \\}
......@@ -84,8 +80,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
8480 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
8581 \\ @import("std").os.exit(126);
8682 \\}
87 \\error Whatever;
88 \\pub fn main() %void {
83 \\pub fn main() !void {
8984 \\ const x = div(-32768, -1);
9085 \\ if (x == 32767) return error.Whatever;
9186 \\}
......@@ -98,8 +93,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
9893 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
9994 \\ @import("std").os.exit(126);
10095 \\}
101 \\error Whatever;
102 \\pub fn main() %void {
96 \\pub fn main() !void {
10397 \\ const x = shl(-16385, 1);
10498 \\ if (x == 0) return error.Whatever;
10599 \\}
......@@ -112,8 +106,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
112106 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
113107 \\ @import("std").os.exit(126);
114108 \\}
115 \\error Whatever;
116 \\pub fn main() %void {
109 \\pub fn main() !void {
117110 \\ const x = shl(0b0010111111111111, 3);
118111 \\ if (x == 0) return error.Whatever;
119112 \\}
......@@ -126,8 +119,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
126119 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
127120 \\ @import("std").os.exit(126);
128121 \\}
129 \\error Whatever;
130 \\pub fn main() %void {
122 \\pub fn main() !void {
131123 \\ const x = shr(-16385, 1);
132124 \\ if (x == 0) return error.Whatever;
133125 \\}
......@@ -140,8 +132,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
140132 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
141133 \\ @import("std").os.exit(126);
142134 \\}
143 \\error Whatever;
144 \\pub fn main() %void {
135 \\pub fn main() !void {
145136 \\ const x = shr(0b0010111111111111, 3);
146137 \\ if (x == 0) return error.Whatever;
147138 \\}
......@@ -154,8 +145,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
154145 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
155146 \\ @import("std").os.exit(126);
156147 \\}
157 \\error Whatever;
158 \\pub fn main() %void {
148 \\pub fn main() void {
159149 \\ const x = div0(999, 0);
160150 \\}
161151 \\fn div0(a: i32, b: i32) i32 {
......@@ -167,8 +157,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
167157 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
168158 \\ @import("std").os.exit(126);
169159 \\}
170 \\error Whatever;
171 \\pub fn main() %void {
160 \\pub fn main() !void {
172161 \\ const x = divExact(10, 3);
173162 \\ if (x == 0) return error.Whatever;
174163 \\}
......@@ -181,8 +170,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
181170 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
182171 \\ @import("std").os.exit(126);
183172 \\}
184 \\error Whatever;
185 \\pub fn main() %void {
173 \\pub fn main() !void {
186174 \\ const x = widenSlice([]u8{1, 2, 3, 4, 5});
187175 \\ if (x.len == 0) return error.Whatever;
188176 \\}
......@@ -195,8 +183,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
195183 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
196184 \\ @import("std").os.exit(126);
197185 \\}
198 \\error Whatever;
199 \\pub fn main() %void {
186 \\pub fn main() !void {
200187 \\ const x = shorten_cast(200);
201188 \\ if (x == 0) return error.Whatever;
202189 \\}
......@@ -209,8 +196,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
209196 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
210197 \\ @import("std").os.exit(126);
211198 \\}
212 \\error Whatever;
213 \\pub fn main() %void {
199 \\pub fn main() !void {
214200 \\ const x = unsigned_cast(-10);
215201 \\ if (x == 0) return error.Whatever;
216202 \\}
......@@ -226,20 +212,19 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
226212 \\ }
227213 \\ @import("std").os.exit(0); // test failed
228214 \\}
229 \\error Whatever;
230 \\pub fn main() %void {
215 \\pub fn main() void {
231216 \\ bar() catch unreachable;
232217 \\}
233 \\fn bar() %void {
218 \\fn bar() !void {
234219 \\ return error.Whatever;
235220 \\}
236221 );
237222
238 cases.addRuntimeSafety("cast integer to error and no code matches",
223 cases.addRuntimeSafety("cast integer to global error and no code matches",
239224 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
240225 \\ @import("std").os.exit(126);
241226 \\}
242 \\pub fn main() %void {
227 \\pub fn main() void {
243228 \\ _ = bar(9999);
244229 \\}
245230 \\fn bar(x: u32) error {
......@@ -247,12 +232,25 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
247232 \\}
248233 );
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
250249 cases.addRuntimeSafety("@alignCast misaligned",
251250 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
252251 \\ @import("std").os.exit(126);
253252 \\}
254 \\error Wrong;
255 \\pub fn main() %void {
253 \\pub fn main() !void {
256254 \\ var array align(4) = []u32{0x11111111, 0x11111111};
257255 \\ const bytes = ([]u8)(array[0..]);
258256 \\ if (foo(bytes) != 0x11111111) return error.Wrong;
......@@ -274,7 +272,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
274272 \\ int: u32,
275273 \\};
276274 \\
277 \\pub fn main() %void {
275 \\pub fn main() void {
278276 \\ var f = Foo { .int = 42 };
279277 \\ bar(&f);
280278 \\}
test/standalone/brace_expansion/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) %void {
3pub fn build(b: &Builder) void {
44 const main = b.addTest("main.zig");
55 main.setBuildMode(b.standardReleaseOptions());
66
test/standalone/brace_expansion/main.zig+14-8
......@@ -6,9 +6,6 @@ const assert = debug.assert;
66const Buffer = std.Buffer;
77const ArrayList = std.ArrayList;
88
9error InvalidInput;
10error OutOfMem;
11
129const Token = union(enum) {
1310 Word: []const u8,
1411 OpenBrace,
......@@ -19,7 +16,7 @@ const Token = union(enum) {
1916
2017var global_allocator: &mem.Allocator = undefined;
2118
22fn tokenize(input:[] const u8) %ArrayList(Token) {
19fn tokenize(input:[] const u8) !ArrayList(Token) {
2320 const State = enum {
2421 Start,
2522 Word,
......@@ -71,7 +68,12 @@ const Node = union(enum) {
7168 Combine: []Node,
7269};
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 {
7577 const first_token = tokens.items[*token_index];
7678 *token_index += 1;
7779
......@@ -107,7 +109,7 @@ fn parse(tokens: &const ArrayList(Token), token_index: &usize) %Node {
107109 }
108110}
109111
110fn expandString(input: []const u8, output: &Buffer) %void {
112fn expandString(input: []const u8, output: &Buffer) !void {
111113 const tokens = try tokenize(input);
112114 if (tokens.len == 1) {
113115 return output.resize(0);
......@@ -135,7 +137,11 @@ fn expandString(input: []const u8, output: &Buffer) %void {
135137 }
136138}
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 {
139145 assert(output.len == 0);
140146 switch (*node) {
141147 Node.Scalar => |scalar| {
......@@ -172,7 +178,7 @@ fn expandNode(node: &const Node, output: &ArrayList(Buffer)) %void {
172178 }
173179}
174180
175pub fn main() %void {
181pub fn main() !void {
176182 var stdin_file = try io.getStdIn();
177183 var stdout_file = try io.getStdOut();
178184
test/standalone/issue_339/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) %void {
3pub fn build(b: &Builder) void {
44 const obj = b.addObject("test", "test.zig");
55
66 const test_step = b.step("test", "Test the program");
test/standalone/issue_339/test.zig+1-1
......@@ -1,7 +1,7 @@
11const StackTrace = @import("builtin").StackTrace;
22pub fn panic(msg: []const u8, stack_trace: ?&StackTrace) noreturn { @breakpoint(); while (true) {} }
33
4fn bar() %void {}
4fn bar() error!void {}
55
66export fn foo() void {
77 bar() catch unreachable;
test/standalone/pkg_import/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) %void {
3pub fn build(b: &Builder) void {
44 const exe = b.addExecutable("test", "test.zig");
55 exe.addPackagePath("my_pkg", "pkg.zig");
66
test/standalone/pkg_import/test.zig+1-1
......@@ -1,6 +1,6 @@
11const my_pkg = @import("my_pkg");
22const assert = @import("std").debug.assert;
33
4pub fn main() %void {
4pub fn main() void {
55 assert(my_pkg.add(10, 20) == 30);
66}
test/standalone/use_alias/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) %void {
3pub fn build(b: &Builder) void {
44 b.addCIncludePath(".");
55
66 const main = b.addTest("main.zig");
test/tests.zig+5-8
......@@ -45,9 +45,6 @@ const test_targets = []TestTarget {
4545 },
4646};
4747
48error TestFailed;
49error CompilationIncorrectlySucceeded;
50
5148const max_stdout_size = 1 * 1024 * 1024; // 1 MB
5249
5350pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
......@@ -248,7 +245,7 @@ pub const CompareOutputContext = struct {
248245 return ptr;
249246 }
250247
251 fn make(step: &build.Step) %void {
248 fn make(step: &build.Step) !void {
252249 const self = @fieldParentPtr(RunCompareOutputStep, "step", step);
253250 const b = self.context.b;
254251
......@@ -337,7 +334,7 @@ pub const CompareOutputContext = struct {
337334 return ptr;
338335 }
339336
340 fn make(step: &build.Step) %void {
337 fn make(step: &build.Step) !void {
341338 const self = @fieldParentPtr(RuntimeSafetyRunStep, "step", step);
342339 const b = self.context.b;
343340
......@@ -563,7 +560,7 @@ pub const CompileErrorContext = struct {
563560 return ptr;
564561 }
565562
566 fn make(step: &build.Step) %void {
563 fn make(step: &build.Step) !void {
567564 const self = @fieldParentPtr(CompileCmpOutputStep, "step", step);
568565 const b = self.context.b;
569566
......@@ -847,7 +844,7 @@ pub const TranslateCContext = struct {
847844 return ptr;
848845 }
849846
850 fn make(step: &build.Step) %void {
847 fn make(step: &build.Step) !void {
851848 const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step);
852849 const b = self.context.b;
853850
......@@ -1045,7 +1042,7 @@ pub const GenHContext = struct {
10451042 return ptr;
10461043 }
10471044
1048 fn make(step: &build.Step) %void {
1045 fn make(step: &build.Step) !void {
10491046 const self = @fieldParentPtr(GenHCmpOutputStep, "step", step);
10501047 const b = self.context.b;
10511048