| author | |
| committer | |
| log | 59119628425566691a6c580a3da378798bc6c648 |
| tree | 7eeeaf4620f40e5a6203c9de91edbdab5e733a51 |
| parent | 1c236b0766bbc68f1b04e32a95683e273b26714c |
| parent | 8e554561df7823e2aba0076f2fc98278df6cb8f2 |
| signature |
Error Sets83 files changed, 3263 insertions(+), 1607 deletions(-)
build.zig+2-2| ... | @@ -10,7 +10,7 @@ const ArrayList = std.ArrayList; | ... | @@ -10,7 +10,7 @@ const ArrayList = std.ArrayList; |
| 10 | const Buffer = std.Buffer; | 10 | const Buffer = std.Buffer; |
| 11 | const io = std.io; | 11 | const io = std.io; |
| 12 | 12 | ||
| 13 | pub fn build(b: &Builder) %void { | 13 | pub fn build(b: &Builder) !void { |
| 14 | const mode = b.standardReleaseOptions(); | 14 | const mode = b.standardReleaseOptions(); |
| 15 | 15 | ||
| 16 | var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig"); | 16 | var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig"); |
| ... | @@ -149,7 +149,7 @@ const LibraryDep = struct { | ... | @@ -149,7 +149,7 @@ const LibraryDep = struct { |
| 149 | includes: ArrayList([]const u8), | 149 | includes: ArrayList([]const u8), |
| 150 | }; | 150 | }; |
| 151 | 151 | ||
| 152 | fn findLLVM(b: &Builder, llvm_config_exe: []const u8) %LibraryDep { | 152 | fn findLLVM(b: &Builder, llvm_config_exe: []const u8) !LibraryDep { |
| 153 | const libs_output = try b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"}); | 153 | const libs_output = try b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"}); |
| 154 | const includes_output = try b.exec([][]const u8{llvm_config_exe, "--includedir"}); | 154 | const includes_output = try b.exec([][]const u8{llvm_config_exe, "--includedir"}); |
| 155 | const libdir_output = try b.exec([][]const u8{llvm_config_exe, "--libdir"}); | 155 | const libdir_output = try b.exec([][]const u8{llvm_config_exe, "--libdir"}); |
ci/appveyor/build_script.bat+3-4| ... | @@ -30,11 +30,10 @@ cd %APPVEYOR_BUILD_FOLDER% | ... | @@ -30,11 +30,10 @@ cd %APPVEYOR_BUILD_FOLDER% |
| 30 | SET "PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%" | 30 | SET "PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%" |
| 31 | SET "MSYSTEM=MINGW64" | 31 | SET "MSYSTEM=MINGW64" |
| 32 | 32 | ||
| 33 | bash -lc "pacman -Syu --needed --noconfirm" | 33 | bash -lc "yes | pacman -Syu --needed --noconfirm" |
| 34 | bash -lc "pacman -Su --needed --noconfirm" | 34 | bash -lc "yes | pacman -Su --needed --noconfirm" |
| 35 | 35 | ||
| 36 | bash -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" | 36 | bash -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" |
| 37 | 37 | ||
| 38 | bash -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" | 38 | bash -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" |
| 39 | 39 | ||
| 40 | @echo "MinGW build successful" |
doc/docgen.zig+10-19| ... | @@ -12,7 +12,7 @@ const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt(); | ... | @@ -12,7 +12,7 @@ const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt(); |
| 12 | const obj_ext = std.build.Target(std.build.Target.Native).oFileExt(); | 12 | const obj_ext = std.build.Target(std.build.Target.Native).oFileExt(); |
| 13 | const tmp_dir_name = "docgen_tmp"; | 13 | const tmp_dir_name = "docgen_tmp"; |
| 14 | 14 | ||
| 15 | pub fn main() %void { | 15 | pub fn main() !void { |
| 16 | // TODO use a more general purpose allocator here | 16 | // TODO use a more general purpose allocator here |
| 17 | var inc_allocator = try std.heap.IncrementingAllocator.init(max_doc_file_size); | 17 | var inc_allocator = try std.heap.IncrementingAllocator.init(max_doc_file_size); |
| 18 | defer inc_allocator.deinit(); | 18 | defer inc_allocator.deinit(); |
| ... | @@ -42,7 +42,7 @@ pub fn main() %void { | ... | @@ -42,7 +42,7 @@ pub fn main() %void { |
| 42 | const input_file_bytes = try file_in_stream.stream.readAllAlloc(allocator, max_doc_file_size); | 42 | const input_file_bytes = try file_in_stream.stream.readAllAlloc(allocator, max_doc_file_size); |
| 43 | 43 | ||
| 44 | var file_out_stream = io.FileOutStream.init(&out_file); | 44 | var file_out_stream = io.FileOutStream.init(&out_file); |
| 45 | var buffered_out_stream = io.BufferedOutStream.init(&file_out_stream.stream); | 45 | var buffered_out_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream); |
| 46 | 46 | ||
| 47 | var tokenizer = Tokenizer.init(in_file_name, input_file_bytes); | 47 | var tokenizer = Tokenizer.init(in_file_name, input_file_bytes); |
| 48 | var toc = try genToc(allocator, &tokenizer); | 48 | var toc = try genToc(allocator, &tokenizer); |
| ... | @@ -218,8 +218,6 @@ const Tokenizer = struct { | ... | @@ -218,8 +218,6 @@ const Tokenizer = struct { |
| 218 | } | 218 | } |
| 219 | }; | 219 | }; |
| 220 | 220 | ||
| 221 | error ParseError; | ||
| 222 | |||
| 223 | fn parseError(tokenizer: &Tokenizer, token: &const Token, comptime fmt: []const u8, args: ...) error { | 221 | fn parseError(tokenizer: &Tokenizer, token: &const Token, comptime fmt: []const u8, args: ...) error { |
| 224 | const loc = tokenizer.getTokenLocation(token); | 222 | const loc = tokenizer.getTokenLocation(token); |
| 225 | warn("{}:{}:{}: error: " ++ fmt ++ "\n", tokenizer.source_file_name, loc.line + 1, loc.column + 1, args); | 223 | warn("{}:{}:{}: error: " ++ fmt ++ "\n", tokenizer.source_file_name, loc.line + 1, loc.column + 1, args); |
| ... | @@ -243,13 +241,13 @@ fn parseError(tokenizer: &Tokenizer, token: &const Token, comptime fmt: []const | ... | @@ -243,13 +241,13 @@ fn parseError(tokenizer: &Tokenizer, token: &const Token, comptime fmt: []const |
| 243 | return error.ParseError; | 241 | return error.ParseError; |
| 244 | } | 242 | } |
| 245 | 243 | ||
| 246 | fn assertToken(tokenizer: &Tokenizer, token: &const Token, id: Token.Id) %void { | 244 | fn assertToken(tokenizer: &Tokenizer, token: &const Token, id: Token.Id) !void { |
| 247 | if (token.id != id) { | 245 | if (token.id != id) { |
| 248 | return parseError(tokenizer, token, "expected {}, found {}", @tagName(id), @tagName(token.id)); | 246 | return parseError(tokenizer, token, "expected {}, found {}", @tagName(id), @tagName(token.id)); |
| 249 | } | 247 | } |
| 250 | } | 248 | } |
| 251 | 249 | ||
| 252 | fn eatToken(tokenizer: &Tokenizer, id: Token.Id) %Token { | 250 | fn eatToken(tokenizer: &Tokenizer, id: Token.Id) !Token { |
| 253 | const token = tokenizer.next(); | 251 | const token = tokenizer.next(); |
| 254 | try assertToken(tokenizer, token, id); | 252 | try assertToken(tokenizer, token, id); |
| 255 | return token; | 253 | return token; |
| ... | @@ -316,7 +314,7 @@ const Action = enum { | ... | @@ -316,7 +314,7 @@ const Action = enum { |
| 316 | Close, | 314 | Close, |
| 317 | }; | 315 | }; |
| 318 | 316 | ||
| 319 | fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) %Toc { | 317 | fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc { |
| 320 | var urls = std.HashMap([]const u8, Token, mem.hash_slice_u8, mem.eql_slice_u8).init(allocator); | 318 | var urls = std.HashMap([]const u8, Token, mem.hash_slice_u8, mem.eql_slice_u8).init(allocator); |
| 321 | errdefer urls.deinit(); | 319 | errdefer urls.deinit(); |
| 322 | 320 | ||
| ... | @@ -540,7 +538,7 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) %Toc { | ... | @@ -540,7 +538,7 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) %Toc { |
| 540 | }; | 538 | }; |
| 541 | } | 539 | } |
| 542 | 540 | ||
| 543 | fn urlize(allocator: &mem.Allocator, input: []const u8) %[]u8 { | 541 | fn urlize(allocator: &mem.Allocator, input: []const u8) ![]u8 { |
| 544 | var buf = try std.Buffer.initSize(allocator, 0); | 542 | var buf = try std.Buffer.initSize(allocator, 0); |
| 545 | defer buf.deinit(); | 543 | defer buf.deinit(); |
| 546 | 544 | ||
| ... | @@ -560,7 +558,7 @@ fn urlize(allocator: &mem.Allocator, input: []const u8) %[]u8 { | ... | @@ -560,7 +558,7 @@ fn urlize(allocator: &mem.Allocator, input: []const u8) %[]u8 { |
| 560 | return buf.toOwnedSlice(); | 558 | return buf.toOwnedSlice(); |
| 561 | } | 559 | } |
| 562 | 560 | ||
| 563 | fn escapeHtml(allocator: &mem.Allocator, input: []const u8) %[]u8 { | 561 | fn escapeHtml(allocator: &mem.Allocator, input: []const u8) ![]u8 { |
| 564 | var buf = try std.Buffer.initSize(allocator, 0); | 562 | var buf = try std.Buffer.initSize(allocator, 0); |
| 565 | defer buf.deinit(); | 563 | defer buf.deinit(); |
| 566 | 564 | ||
| ... | @@ -596,15 +594,13 @@ const TermState = enum { | ... | @@ -596,15 +594,13 @@ const TermState = enum { |
| 596 | ExpectEnd, | 594 | ExpectEnd, |
| 597 | }; | 595 | }; |
| 598 | 596 | ||
| 599 | error UnsupportedEscape; | ||
| 600 | |||
| 601 | test "term color" { | 597 | test "term color" { |
| 602 | const input_bytes = "A\x1b[32;1mgreen\x1b[0mB"; | 598 | const input_bytes = "A\x1b[32;1mgreen\x1b[0mB"; |
| 603 | const result = try termColor(std.debug.global_allocator, input_bytes); | 599 | const result = try termColor(std.debug.global_allocator, input_bytes); |
| 604 | assert(mem.eql(u8, result, "A<span class=\"t32\">green</span>B")); | 600 | assert(mem.eql(u8, result, "A<span class=\"t32\">green</span>B")); |
| 605 | } | 601 | } |
| 606 | 602 | ||
| 607 | fn termColor(allocator: &mem.Allocator, input: []const u8) %[]u8 { | 603 | fn termColor(allocator: &mem.Allocator, input: []const u8) ![]u8 { |
| 608 | var buf = try std.Buffer.initSize(allocator, 0); | 604 | var buf = try std.Buffer.initSize(allocator, 0); |
| 609 | defer buf.deinit(); | 605 | defer buf.deinit(); |
| 610 | 606 | ||
| ... | @@ -684,9 +680,7 @@ fn termColor(allocator: &mem.Allocator, input: []const u8) %[]u8 { | ... | @@ -684,9 +680,7 @@ fn termColor(allocator: &mem.Allocator, input: []const u8) %[]u8 { |
| 684 | return buf.toOwnedSlice(); | 680 | return buf.toOwnedSlice(); |
| 685 | } | 681 | } |
| 686 | 682 | ||
| 687 | error ExampleFailedToCompile; | 683 | fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var, zig_exe: []const u8) !void { |
| 688 | |||
| 689 | fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io.OutStream, zig_exe: []const u8) %void { | ||
| 690 | var code_progress_index: usize = 0; | 684 | var code_progress_index: usize = 0; |
| 691 | for (toc.nodes) |node| { | 685 | for (toc.nodes) |node| { |
| 692 | switch (node) { | 686 | switch (node) { |
| ... | @@ -974,10 +968,7 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io | ... | @@ -974,10 +968,7 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io |
| 974 | 968 | ||
| 975 | } | 969 | } |
| 976 | 970 | ||
| 977 | error ChildCrashed; | 971 | fn exec(allocator: &mem.Allocator, args: []const []const u8) !os.ChildProcess.ExecResult { |
| 978 | error ChildExitError; | ||
| 979 | |||
| 980 | fn exec(allocator: &mem.Allocator, args: []const []const u8) %os.ChildProcess.ExecResult { | ||
| 981 | const result = try os.ChildProcess.exec(allocator, args, null, null, max_doc_file_size); | 972 | const result = try os.ChildProcess.exec(allocator, args, null, null, max_doc_file_size); |
| 982 | switch (result.term) { | 973 | switch (result.term) { |
| 983 | os.ChildProcess.Term.Exited => |exit_code| { | 974 | os.ChildProcess.Term.Exited => |exit_code| { |
doc/langref.html.in+62-76| ... | @@ -108,7 +108,7 @@ | ... | @@ -108,7 +108,7 @@ |
| 108 | {#code_begin|exe|hello#} | 108 | {#code_begin|exe|hello#} |
| 109 | const std = @import("std"); | 109 | const std = @import("std"); |
| 110 | 110 | ||
| 111 | pub fn main() %void { | 111 | pub fn main() !void { |
| 112 | // If this program is run without stdout attached, exit with an error. | 112 | // If this program is run without stdout attached, exit with an error. |
| 113 | var stdout_file = try std.io.getStdOut(); | 113 | var stdout_file = try std.io.getStdOut(); |
| 114 | // If this program encounters pipe failure when printing to stdout, exit | 114 | // If this program encounters pipe failure when printing to stdout, exit |
| ... | @@ -129,8 +129,8 @@ pub fn main() void { | ... | @@ -129,8 +129,8 @@ pub fn main() void { |
| 129 | } | 129 | } |
| 130 | {#code_end#} | 130 | {#code_end#} |
| 131 | <p> | 131 | <p> |
| 132 | Note that we also left off the <code class="zig">%</code> from the return type. | 132 | Note that we also left off the <code class="zig">!</code> from the return type. |
| 133 | In Zig, if your main function cannot fail, you may use the <code class="zig">void</code> return type. | 133 | In Zig, if your main function cannot fail, you must use the <code class="zig">void</code> return type. |
| 134 | </p> | 134 | </p> |
| 135 | {#see_also|Values|@import|Errors|Root Source File#} | 135 | {#see_also|Values|@import|Errors|Root Source File#} |
| 136 | {#header_close#} | 136 | {#header_close#} |
| ... | @@ -141,10 +141,7 @@ const warn = std.debug.warn; | ... | @@ -141,10 +141,7 @@ const warn = std.debug.warn; |
| 141 | const os = std.os; | 141 | const os = std.os; |
| 142 | const assert = std.debug.assert; | 142 | const assert = std.debug.assert; |
| 143 | 143 | ||
| 144 | // error declaration, makes `error.ArgNotFound` available | 144 | pub fn main() void { |
| 145 | error ArgNotFound; | ||
| 146 | |||
| 147 | pub fn main() %void { | ||
| 148 | // integers | 145 | // integers |
| 149 | const one_plus_one: i32 = 1 + 1; | 146 | const one_plus_one: i32 = 1 + 1; |
| 150 | warn("1 + 1 = {}\n", one_plus_one); | 147 | warn("1 + 1 = {}\n", one_plus_one); |
| ... | @@ -173,7 +170,7 @@ pub fn main() %void { | ... | @@ -173,7 +170,7 @@ pub fn main() %void { |
| 173 | @typeName(@typeOf(nullable_value)), nullable_value); | 170 | @typeName(@typeOf(nullable_value)), nullable_value); |
| 174 | 171 | ||
| 175 | // error union | 172 | // error union |
| 176 | var number_or_error: %i32 = error.ArgNotFound; | 173 | var number_or_error: error!i32 = error.ArgNotFound; |
| 177 | 174 | ||
| 178 | warn("\nerror union 1\ntype: {}\nvalue: {}\n", | 175 | warn("\nerror union 1\ntype: {}\nvalue: {}\n", |
| 179 | @typeName(@typeOf(number_or_error)), number_or_error); | 176 | @typeName(@typeOf(number_or_error)), number_or_error); |
| ... | @@ -681,7 +678,7 @@ const warn = @import("std").debug.warn; | ... | @@ -681,7 +678,7 @@ const warn = @import("std").debug.warn; |
| 681 | extern fn foo_strict(x: f64) f64; | 678 | extern fn foo_strict(x: f64) f64; |
| 682 | extern fn foo_optimized(x: f64) f64; | 679 | extern fn foo_optimized(x: f64) f64; |
| 683 | 680 | ||
| 684 | pub fn main() %void { | 681 | pub fn main() void { |
| 685 | const x = 0.001; | 682 | const x = 0.001; |
| 686 | warn("optimized = {}\n", foo_optimized(x)); | 683 | warn("optimized = {}\n", foo_optimized(x)); |
| 687 | warn("strict = {}\n", foo_strict(x)); | 684 | warn("strict = {}\n", foo_strict(x)); |
| ... | @@ -1036,7 +1033,7 @@ a catch |err| b</code></pre></td> | ... | @@ -1036,7 +1033,7 @@ a catch |err| b</code></pre></td> |
| 1036 | <code>err</code> is the <code>error</code> and is in scope of the expression <code>b</code>. | 1033 | <code>err</code> is the <code>error</code> and is in scope of the expression <code>b</code>. |
| 1037 | </td> | 1034 | </td> |
| 1038 | <td> | 1035 | <td> |
| 1039 | <pre><code class="zig">const value: %u32 = null; | 1036 | <pre><code class="zig">const value: error!u32 = error.Broken; |
| 1040 | const unwrapped = value catch 1234; | 1037 | const unwrapped = value catch 1234; |
| 1041 | unwrapped == 1234</code></pre> | 1038 | unwrapped == 1234</code></pre> |
| 1042 | </td> | 1039 | </td> |
| ... | @@ -1269,9 +1266,10 @@ const ptr = &amp;x; | ... | @@ -1269,9 +1266,10 @@ const ptr = &amp;x; |
| 1269 | {#header_close#} | 1266 | {#header_close#} |
| 1270 | {#header_open|Precedence#} | 1267 | {#header_open|Precedence#} |
| 1271 | <pre><code>x() x[] x.y | 1268 | <pre><code>x() x[] x.y |
| 1272 | !x -x -%x ~x *x &amp;x ?x %x ??x | 1269 | a!b |
| 1270 | !x -x -%x ~x *x &amp;x ?x ??x | ||
| 1273 | x{} | 1271 | x{} |
| 1274 | * / % ** *% | 1272 | ! * / % ** *% |
| 1275 | + - ++ +% -% | 1273 | + - ++ +% -% |
| 1276 | &lt;&lt; &gt;&gt; | 1274 | &lt;&lt; &gt;&gt; |
| 1277 | &amp; | 1275 | &amp; |
| ... | @@ -2268,8 +2266,8 @@ fn eventuallyNullSequence() ?u32 { | ... | @@ -2268,8 +2266,8 @@ fn eventuallyNullSequence() ?u32 { |
| 2268 | break :blk numbers_left; | 2266 | break :blk numbers_left; |
| 2269 | }; | 2267 | }; |
| 2270 | } | 2268 | } |
| 2271 | error ReachedZero; | 2269 | |
| 2272 | fn eventuallyErrorSequence() %u32 { | 2270 | fn eventuallyErrorSequence() error!u32 { |
| 2273 | return if (numbers_left == 0) error.ReachedZero else blk: { | 2271 | return if (numbers_left == 0) error.ReachedZero else blk: { |
| 2274 | numbers_left -= 1; | 2272 | numbers_left -= 1; |
| 2275 | break :blk numbers_left; | 2273 | break :blk numbers_left; |
| ... | @@ -2398,7 +2396,7 @@ fn typeNameLength(comptime T: type) usize { | ... | @@ -2398,7 +2396,7 @@ fn typeNameLength(comptime T: type) usize { |
| 2398 | // If expressions have three uses, corresponding to the three types: | 2396 | // If expressions have three uses, corresponding to the three types: |
| 2399 | // * bool | 2397 | // * bool |
| 2400 | // * ?T | 2398 | // * ?T |
| 2401 | // * %T | 2399 | // * error!T |
| 2402 | 2400 | ||
| 2403 | const assert = @import("std").debug.assert; | 2401 | const assert = @import("std").debug.assert; |
| 2404 | 2402 | ||
| ... | @@ -2459,20 +2457,18 @@ test "if nullable" { | ... | @@ -2459,20 +2457,18 @@ test "if nullable" { |
| 2459 | } | 2457 | } |
| 2460 | } | 2458 | } |
| 2461 | 2459 | ||
| 2462 | error BadValue; | ||
| 2463 | error LessBadValue; | ||
| 2464 | test "if error union" { | 2460 | test "if error union" { |
| 2465 | // If expressions test for errors. | 2461 | // If expressions test for errors. |
| 2466 | // Note the |err| capture on the else. | 2462 | // Note the |err| capture on the else. |
| 2467 | 2463 | ||
| 2468 | const a: %u32 = 0; | 2464 | const a: error!u32 = 0; |
| 2469 | if (a) |value| { | 2465 | if (a) |value| { |
| 2470 | assert(value == 0); | 2466 | assert(value == 0); |
| 2471 | } else |err| { | 2467 | } else |err| { |
| 2472 | unreachable; | 2468 | unreachable; |
| 2473 | } | 2469 | } |
| 2474 | 2470 | ||
| 2475 | const b: %u32 = error.BadValue; | 2471 | const b: error!u32 = error.BadValue; |
| 2476 | if (b) |value| { | 2472 | if (b) |value| { |
| 2477 | unreachable; | 2473 | unreachable; |
| 2478 | } else |err| { | 2474 | } else |err| { |
| ... | @@ -2490,7 +2486,7 @@ test "if error union" { | ... | @@ -2490,7 +2486,7 @@ test "if error union" { |
| 2490 | } | 2486 | } |
| 2491 | 2487 | ||
| 2492 | // Access the value by reference using a pointer capture. | 2488 | // Access the value by reference using a pointer capture. |
| 2493 | var c: %u32 = 3; | 2489 | var c: error!u32 = 3; |
| 2494 | if (c) |*value| { | 2490 | if (c) |*value| { |
| 2495 | *value = 9; | 2491 | *value = 9; |
| 2496 | } else |err| { | 2492 | } else |err| { |
| ... | @@ -2558,8 +2554,7 @@ test "defer unwinding" { | ... | @@ -2558,8 +2554,7 @@ test "defer unwinding" { |
| 2558 | // | 2554 | // |
| 2559 | // This is especially useful in allowing a function to clean up properly | 2555 | // This is especially useful in allowing a function to clean up properly |
| 2560 | // on error, and replaces goto error handling tactics as seen in c. | 2556 | // on error, and replaces goto error handling tactics as seen in c. |
| 2561 | error DeferError; | 2557 | fn deferErrorExample(is_error: bool) !void { |
| 2562 | fn deferErrorExample(is_error: bool) %void { | ||
| 2563 | warn("\nstart of function\n"); | 2558 | warn("\nstart of function\n"); |
| 2564 | 2559 | ||
| 2565 | // This will always be executed on exit | 2560 | // This will always be executed on exit |
| ... | @@ -2668,7 +2663,7 @@ test "foo" { | ... | @@ -2668,7 +2663,7 @@ test "foo" { |
| 2668 | assert(value == 1234); | 2663 | assert(value == 1234); |
| 2669 | } | 2664 | } |
| 2670 | 2665 | ||
| 2671 | fn bar() %u32 { | 2666 | fn bar() error!u32 { |
| 2672 | return 1234; | 2667 | return 1234; |
| 2673 | } | 2668 | } |
| 2674 | 2669 | ||
| ... | @@ -2791,13 +2786,8 @@ test "fn reflection" { | ... | @@ -2791,13 +2786,8 @@ test "fn reflection" { |
| 2791 | One of the distinguishing features of Zig is its exception handling strategy. | 2786 | One of the distinguishing features of Zig is its exception handling strategy. |
| 2792 | </p> | 2787 | </p> |
| 2793 | <p> | 2788 | <p> |
| 2794 | Among the top level declarations available is the error value declaration: | 2789 | TODO rewrite the errors section to take into account error sets |
| 2795 | </p> | 2790 | </p> |
| 2796 | {#code_begin|syntax#} | ||
| 2797 | error FileNotFound; | ||
| 2798 | error OutOfMemory; | ||
| 2799 | error UnexpectedToken; | ||
| 2800 | {#code_end#} | ||
| 2801 | <p> | 2791 | <p> |
| 2802 | These error values are assigned an unsigned integer value greater than 0 at | 2792 | These error values are assigned an unsigned integer value greater than 0 at |
| 2803 | compile time. You are allowed to declare the same error value more than once, | 2793 | compile time. You are allowed to declare the same error value more than once, |
| ... | @@ -2809,26 +2799,23 @@ error UnexpectedToken; | ... | @@ -2809,26 +2799,23 @@ error UnexpectedToken; |
| 2809 | </p> | 2799 | </p> |
| 2810 | <p> | 2800 | <p> |
| 2811 | Each error value across the entire compilation unit gets a unique integer, | 2801 | Each error value across the entire compilation unit gets a unique integer, |
| 2812 | and this determines the size of the pure error type. | 2802 | and this determines the size of the error set type. |
| 2813 | </p> | 2803 | </p> |
| 2814 | <p> | 2804 | <p> |
| 2815 | The pure error type is one of the error values, and in the same way that pointers | 2805 | The error set type is one of the error values, and in the same way that pointers |
| 2816 | cannot be null, a pure error is always an error. | 2806 | cannot be null, a error set instance is always an error. |
| 2817 | </p> | 2807 | </p> |
| 2818 | {#code_begin|syntax#}const pure_error = error.FileNotFound;{#code_end#} | 2808 | {#code_begin|syntax#}const pure_error = error.FileNotFound;{#code_end#} |
| 2819 | <p> | 2809 | <p> |
| 2820 | Most of the time you will not find yourself using a pure error type. Instead, | 2810 | Most of the time you will not find yourself using an error set type. Instead, |
| 2821 | likely you will be using the error union type. This is when you take a normal type, | 2811 | likely you will be using the error union type. This is when you take an error set |
| 2822 | and prefix it with the <code>%</code> operator. | 2812 | and a normal type, and create an error union with the <code>!</code> binary operator. |
| 2823 | </p> | 2813 | </p> |
| 2824 | <p> | 2814 | <p> |
| 2825 | Here is a function to parse a string into a 64-bit integer: | 2815 | Here is a function to parse a string into a 64-bit integer: |
| 2826 | </p> | 2816 | </p> |
| 2827 | {#code_begin|test#} | 2817 | {#code_begin|test#} |
| 2828 | error InvalidChar; | 2818 | pub fn parseU64(buf: []const u8, radix: u8) !u64 { |
| 2829 | error Overflow; | ||
| 2830 | |||
| 2831 | pub fn parseU64(buf: []const u8, radix: u8) %u64 { | ||
| 2832 | var x: u64 = 0; | 2819 | var x: u64 = 0; |
| 2833 | 2820 | ||
| 2834 | for (buf) |c| { | 2821 | for (buf) |c| { |
| ... | @@ -2867,13 +2854,14 @@ test "parse u64" { | ... | @@ -2867,13 +2854,14 @@ test "parse u64" { |
| 2867 | } | 2854 | } |
| 2868 | {#code_end#} | 2855 | {#code_end#} |
| 2869 | <p> | 2856 | <p> |
| 2870 | Notice the return type is <code>%u64</code>. This means that the function | 2857 | Notice the return type is <code>!u64</code>. This means that the function |
| 2871 | either returns an unsigned 64 bit integer, or an error. | 2858 | either returns an unsigned 64 bit integer, or an error. We left off the error set |
| 2859 | to the left of the <code>!</code>, so the error set is inferred. | ||
| 2872 | </p> | 2860 | </p> |
| 2873 | <p> | 2861 | <p> |
| 2874 | Within the function definition, you can see some return statements that return | 2862 | Within the function definition, you can see some return statements that return |
| 2875 | a pure error, and at the bottom a return statement that returns a <code>u64</code>. | 2863 | an error, and at the bottom a return statement that returns a <code>u64</code>. |
| 2876 | Both types implicitly cast to <code>%u64</code>. | 2864 | Both types implicitly cast to <code>error!u64</code>. |
| 2877 | </p> | 2865 | </p> |
| 2878 | <p> | 2866 | <p> |
| 2879 | What it looks like to use this function varies depending on what you're | 2867 | What it looks like to use this function varies depending on what you're |
| ... | @@ -2900,7 +2888,7 @@ fn doAThing(str: []u8) void { | ... | @@ -2900,7 +2888,7 @@ fn doAThing(str: []u8) void { |
| 2900 | <p>Let's say you wanted to return the error if you got one, otherwise continue with the | 2888 | <p>Let's say you wanted to return the error if you got one, otherwise continue with the |
| 2901 | function logic:</p> | 2889 | function logic:</p> |
| 2902 | {#code_begin|syntax#} | 2890 | {#code_begin|syntax#} |
| 2903 | fn doAThing(str: []u8) %void { | 2891 | fn doAThing(str: []u8) !void { |
| 2904 | const number = parseU64(str, 10) catch |err| return err; | 2892 | const number = parseU64(str, 10) catch |err| return err; |
| 2905 | // ... | 2893 | // ... |
| 2906 | } | 2894 | } |
| ... | @@ -2909,7 +2897,7 @@ fn doAThing(str: []u8) %void { | ... | @@ -2909,7 +2897,7 @@ fn doAThing(str: []u8) %void { |
| 2909 | There is a shortcut for this. The <code>try</code> expression: | 2897 | There is a shortcut for this. The <code>try</code> expression: |
| 2910 | </p> | 2898 | </p> |
| 2911 | {#code_begin|syntax#} | 2899 | {#code_begin|syntax#} |
| 2912 | fn doAThing(str: []u8) %void { | 2900 | fn doAThing(str: []u8) !void { |
| 2913 | const number = try parseU64(str, 10); | 2901 | const number = try parseU64(str, 10); |
| 2914 | // ... | 2902 | // ... |
| 2915 | } | 2903 | } |
| ... | @@ -2959,7 +2947,7 @@ fn doAThing(str: []u8) void { | ... | @@ -2959,7 +2947,7 @@ fn doAThing(str: []u8) void { |
| 2959 | Example: | 2947 | Example: |
| 2960 | </p> | 2948 | </p> |
| 2961 | {#code_begin|syntax#} | 2949 | {#code_begin|syntax#} |
| 2962 | fn createFoo(param: i32) %Foo { | 2950 | fn createFoo(param: i32) !Foo { |
| 2963 | const foo = try tryToAllocateFoo(); | 2951 | const foo = try tryToAllocateFoo(); |
| 2964 | // now we have allocated foo. we need to free it if the function fails. | 2952 | // now we have allocated foo. we need to free it if the function fails. |
| 2965 | // but we want to return it if the function succeeds. | 2953 | // but we want to return it if the function succeeds. |
| ... | @@ -2999,15 +2987,13 @@ fn createFoo(param: i32) %Foo { | ... | @@ -2999,15 +2987,13 @@ fn createFoo(param: i32) %Foo { |
| 2999 | </ul> | 2987 | </ul> |
| 3000 | {#see_also|defer|if|switch#} | 2988 | {#see_also|defer|if|switch#} |
| 3001 | {#header_open|Error Union Type#} | 2989 | {#header_open|Error Union Type#} |
| 3002 | <p>An error union is created by putting a <code>%</code> in front of a type. | 2990 | <p>An error union is created with the <code>!</code> binary operator. |
| 3003 | You can use compile-time reflection to access the child type of an error union:</p> | 2991 | You can use compile-time reflection to access the child type of an error union:</p> |
| 3004 | {#code_begin|test#} | 2992 | {#code_begin|test#} |
| 3005 | const assert = @import("std").debug.assert; | 2993 | const assert = @import("std").debug.assert; |
| 3006 | 2994 | ||
| 3007 | error SomeError; | ||
| 3008 | |||
| 3009 | test "error union" { | 2995 | test "error union" { |
| 3010 | var foo: %i32 = undefined; | 2996 | var foo: error!i32 = undefined; |
| 3011 | 2997 | ||
| 3012 | // Implicitly cast from child type of an error union: | 2998 | // Implicitly cast from child type of an error union: |
| 3013 | foo = 1234; | 2999 | foo = 1234; |
| ... | @@ -3015,8 +3001,11 @@ test "error union" { | ... | @@ -3015,8 +3001,11 @@ test "error union" { |
| 3015 | // Implicitly cast from an error set: | 3001 | // Implicitly cast from an error set: |
| 3016 | foo = error.SomeError; | 3002 | foo = error.SomeError; |
| 3017 | 3003 | ||
| 3018 | // Use compile-time reflection to access the child type of an error union: | 3004 | // Use compile-time reflection to access the payload type of an error union: |
| 3019 | comptime assert(@typeOf(foo).Child == i32); | 3005 | comptime assert(@typeOf(foo).Payload == i32); |
| 3006 | |||
| 3007 | // Use compile-time reflection to access the error set type of an error union: | ||
| 3008 | comptime assert(@typeOf(foo).ErrorSet == error); | ||
| 3020 | } | 3009 | } |
| 3021 | {#code_end#} | 3010 | {#code_end#} |
| 3022 | {#header_close#} | 3011 | {#header_close#} |
| ... | @@ -3610,7 +3599,7 @@ pub fn main() void { | ... | @@ -3610,7 +3599,7 @@ pub fn main() void { |
| 3610 | 3599 | ||
| 3611 | {#code_begin|syntax#} | 3600 | {#code_begin|syntax#} |
| 3612 | /// Calls print and then flushes the buffer. | 3601 | /// Calls print and then flushes the buffer. |
| 3613 | pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) %void { | 3602 | pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) error!void { |
| 3614 | const State = enum { | 3603 | const State = enum { |
| 3615 | Start, | 3604 | Start, |
| 3616 | OpenBrace, | 3605 | OpenBrace, |
| ... | @@ -3682,7 +3671,7 @@ pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) %void { | ... | @@ -3682,7 +3671,7 @@ pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) %void { |
| 3682 | and emits a function that actually looks like this: | 3671 | and emits a function that actually looks like this: |
| 3683 | </p> | 3672 | </p> |
| 3684 | {#code_begin|syntax#} | 3673 | {#code_begin|syntax#} |
| 3685 | pub fn printf(self: &OutStream, arg0: i32, arg1: []const u8) %void { | 3674 | pub fn printf(self: &OutStream, arg0: i32, arg1: []const u8) !void { |
| 3686 | try self.write("here is a string: '"); | 3675 | try self.write("here is a string: '"); |
| 3687 | try self.printValue(arg0); | 3676 | try self.printValue(arg0); |
| 3688 | try self.write("' here is a number: "); | 3677 | try self.write("' here is a number: "); |
| ... | @@ -3696,7 +3685,7 @@ pub fn printf(self: &OutStream, arg0: i32, arg1: []const u8) %void { | ... | @@ -3696,7 +3685,7 @@ pub fn printf(self: &OutStream, arg0: i32, arg1: []const u8) %void { |
| 3696 | on the type: | 3685 | on the type: |
| 3697 | </p> | 3686 | </p> |
| 3698 | {#code_begin|syntax#} | 3687 | {#code_begin|syntax#} |
| 3699 | pub fn printValue(self: &OutStream, value: var) %void { | 3688 | pub fn printValue(self: &OutStream, value: var) !void { |
| 3700 | const T = @typeOf(value); | 3689 | const T = @typeOf(value); |
| 3701 | if (@isInteger(T)) { | 3690 | if (@isInteger(T)) { |
| 3702 | return self.printInt(T, value); | 3691 | return self.printInt(T, value); |
| ... | @@ -4647,7 +4636,7 @@ pub const TypeId = enum { | ... | @@ -4647,7 +4636,7 @@ pub const TypeId = enum { |
| 4647 | {#code_begin|syntax#} | 4636 | {#code_begin|syntax#} |
| 4648 | const Builder = @import("std").build.Builder; | 4637 | const Builder = @import("std").build.Builder; |
| 4649 | 4638 | ||
| 4650 | pub fn build(b: &Builder) %void { | 4639 | pub fn build(b: &Builder) void { |
| 4651 | const exe = b.addExecutable("example", "example.zig"); | 4640 | const exe = b.addExecutable("example", "example.zig"); |
| 4652 | exe.setBuildMode(b.standardReleaseOptions()); | 4641 | exe.setBuildMode(b.standardReleaseOptions()); |
| 4653 | b.default_step.dependOn(&exe.step); | 4642 | b.default_step.dependOn(&exe.step); |
| ... | @@ -4789,7 +4778,7 @@ comptime { | ... | @@ -4789,7 +4778,7 @@ comptime { |
| 4789 | {#code_begin|exe_err#} | 4778 | {#code_begin|exe_err#} |
| 4790 | const math = @import("std").math; | 4779 | const math = @import("std").math; |
| 4791 | const warn = @import("std").debug.warn; | 4780 | const warn = @import("std").debug.warn; |
| 4792 | pub fn main() %void { | 4781 | pub fn main() !void { |
| 4793 | var byte: u8 = 255; | 4782 | var byte: u8 = 255; |
| 4794 | 4783 | ||
| 4795 | byte = if (math.add(u8, byte, 1)) |result| result else |err| { | 4784 | byte = if (math.add(u8, byte, 1)) |result| result else |err| { |
| ... | @@ -4817,7 +4806,7 @@ pub fn main() %void { | ... | @@ -4817,7 +4806,7 @@ pub fn main() %void { |
| 4817 | </p> | 4806 | </p> |
| 4818 | {#code_begin|exe#} | 4807 | {#code_begin|exe#} |
| 4819 | const warn = @import("std").debug.warn; | 4808 | const warn = @import("std").debug.warn; |
| 4820 | pub fn main() %void { | 4809 | pub fn main() void { |
| 4821 | var byte: u8 = 255; | 4810 | var byte: u8 = 255; |
| 4822 | 4811 | ||
| 4823 | var result: u8 = undefined; | 4812 | var result: u8 = undefined; |
| ... | @@ -4926,14 +4915,12 @@ pub fn main() void { | ... | @@ -4926,14 +4915,12 @@ pub fn main() void { |
| 4926 | {#header_close#} | 4915 | {#header_close#} |
| 4927 | {#header_open|Attempt to Unwrap Error#} | 4916 | {#header_open|Attempt to Unwrap Error#} |
| 4928 | <p>At compile-time:</p> | 4917 | <p>At compile-time:</p> |
| 4929 | {#code_begin|test_err|unable to unwrap error 'UnableToReturnNumber'#} | 4918 | {#code_begin|test_err|caught unexpected error 'UnableToReturnNumber'#} |
| 4930 | comptime { | 4919 | comptime { |
| 4931 | const number = getNumberOrFail() catch unreachable; | 4920 | const number = getNumberOrFail() catch unreachable; |
| 4932 | } | 4921 | } |
| 4933 | 4922 | ||
| 4934 | error UnableToReturnNumber; | 4923 | fn getNumberOrFail() !i32 { |
| 4935 | |||
| 4936 | fn getNumberOrFail() %i32 { | ||
| 4937 | return error.UnableToReturnNumber; | 4924 | return error.UnableToReturnNumber; |
| 4938 | } | 4925 | } |
| 4939 | {#code_end#} | 4926 | {#code_end#} |
| ... | @@ -4953,9 +4940,7 @@ pub fn main() void { | ... | @@ -4953,9 +4940,7 @@ pub fn main() void { |
| 4953 | } | 4940 | } |
| 4954 | } | 4941 | } |
| 4955 | 4942 | ||
| 4956 | error UnableToReturnNumber; | 4943 | fn getNumberOrFail() !i32 { |
| 4957 | |||
| 4958 | fn getNumberOrFail() %i32 { | ||
| 4959 | return error.UnableToReturnNumber; | 4944 | return error.UnableToReturnNumber; |
| 4960 | } | 4945 | } |
| 4961 | {#code_end#} | 4946 | {#code_end#} |
| ... | @@ -4963,7 +4948,6 @@ fn getNumberOrFail() %i32 { | ... | @@ -4963,7 +4948,6 @@ fn getNumberOrFail() %i32 { |
| 4963 | {#header_open|Invalid Error Code#} | 4948 | {#header_open|Invalid Error Code#} |
| 4964 | <p>At compile-time:</p> | 4949 | <p>At compile-time:</p> |
| 4965 | {#code_begin|test_err|integer value 11 represents no error#} | 4950 | {#code_begin|test_err|integer value 11 represents no error#} |
| 4966 | error AnError; | ||
| 4967 | comptime { | 4951 | comptime { |
| 4968 | const err = error.AnError; | 4952 | const err = error.AnError; |
| 4969 | const number = u32(err) + 10; | 4953 | const number = u32(err) + 10; |
| ... | @@ -5363,7 +5347,7 @@ int main(int argc, char **argv) { | ... | @@ -5363,7 +5347,7 @@ int main(int argc, char **argv) { |
| 5363 | {#code_begin|syntax#} | 5347 | {#code_begin|syntax#} |
| 5364 | const Builder = @import("std").build.Builder; | 5348 | const Builder = @import("std").build.Builder; |
| 5365 | 5349 | ||
| 5366 | pub fn build(b: &Builder) %void { | 5350 | pub fn build(b: &Builder) void { |
| 5367 | const obj = b.addObject("base64", "base64.zig"); | 5351 | const obj = b.addObject("base64", "base64.zig"); |
| 5368 | 5352 | ||
| 5369 | const exe = b.addCExecutable("test"); | 5353 | const exe = b.addCExecutable("test"); |
| ... | @@ -5641,14 +5625,12 @@ fn readU32Be() u32 {} | ... | @@ -5641,14 +5625,12 @@ fn readU32Be() u32 {} |
| 5641 | {#header_open|Grammar#} | 5625 | {#header_open|Grammar#} |
| 5642 | <pre><code class="nohighlight">Root = many(TopLevelItem) EOF | 5626 | <pre><code class="nohighlight">Root = many(TopLevelItem) EOF |
| 5643 | 5627 | ||
| 5644 | TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestDecl | 5628 | TopLevelItem = CompTimeExpression(Block) | TopLevelDecl | TestDecl |
| 5645 | 5629 | ||
| 5646 | TestDecl = "test" String Block | 5630 | TestDecl = "test" String Block |
| 5647 | 5631 | ||
| 5648 | TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl) | 5632 | TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl) |
| 5649 | 5633 | ||
| 5650 | ErrorValueDecl = "error" Symbol ";" | ||
| 5651 | |||
| 5652 | GlobalVarDecl = option("export") VariableDeclaration ";" | 5634 | GlobalVarDecl = option("export") VariableDeclaration ";" |
| 5653 | 5635 | ||
| 5654 | LocalVarDecl = option("comptime") VariableDeclaration | 5636 | LocalVarDecl = option("comptime") VariableDeclaration |
| ... | @@ -5663,7 +5645,7 @@ UseDecl = "use" Expression ";" | ... | @@ -5663,7 +5645,7 @@ UseDecl = "use" Expression ";" |
| 5663 | 5645 | ||
| 5664 | ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";" | 5646 | ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";" |
| 5665 | 5647 | ||
| 5666 | FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") TypeExpr | 5648 | FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr |
| 5667 | 5649 | ||
| 5668 | FnDef = option("inline" | "export") FnProto Block | 5650 | FnDef = option("inline" | "export") FnProto Block |
| 5669 | 5651 | ||
| ... | @@ -5675,7 +5657,9 @@ Block = option(Symbol ":") "{" many(Statement) "}" | ... | @@ -5675,7 +5657,9 @@ Block = option(Symbol ":") "{" many(Statement) "}" |
| 5675 | 5657 | ||
| 5676 | Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" | 5658 | Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" |
| 5677 | 5659 | ||
| 5678 | TypeExpr = PrefixOpExpression | "var" | 5660 | TypeExpr = ErrorSetExpr | "var" |
| 5661 | |||
| 5662 | ErrorSetExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression | ||
| 5679 | 5663 | ||
| 5680 | BlockOrExpression = Block | Expression | 5664 | BlockOrExpression = Block | Expression |
| 5681 | 5665 | ||
| ... | @@ -5757,9 +5741,9 @@ MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression | | ... | @@ -5757,9 +5741,9 @@ MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression | |
| 5757 | 5741 | ||
| 5758 | CurlySuffixExpression = TypeExpr option(ContainerInitExpression) | 5742 | CurlySuffixExpression = TypeExpr option(ContainerInitExpression) |
| 5759 | 5743 | ||
| 5760 | MultiplyOperator = "*" | "/" | "%" | "**" | "*%" | 5744 | MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%" |
| 5761 | 5745 | ||
| 5762 | PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression | 5746 | PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression |
| 5763 | 5747 | ||
| 5764 | SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) | 5748 | SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) |
| 5765 | 5749 | ||
| ... | @@ -5777,9 +5761,9 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",") | ... | @@ -5777,9 +5761,9 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",") |
| 5777 | 5761 | ||
| 5778 | StructLiteralField = "." Symbol "=" Expression | 5762 | StructLiteralField = "." Symbol "=" Expression |
| 5779 | 5763 | ||
| 5780 | PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "%" | "??" | "-%" | "try" | 5764 | PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" |
| 5781 | 5765 | ||
| 5782 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl | ("continue" option(":" Symbol)) | 5766 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl |
| 5783 | 5767 | ||
| 5784 | ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr | 5768 | ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr |
| 5785 | 5769 | ||
| ... | @@ -5787,6 +5771,8 @@ GroupedExpression = "(" Expression ")" | ... | @@ -5787,6 +5771,8 @@ GroupedExpression = "(" Expression ")" |
| 5787 | 5771 | ||
| 5788 | KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | 5772 | KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" |
| 5789 | 5773 | ||
| 5774 | ErrorSetDecl = "error" "{" list(Symbol, ",") "}" | ||
| 5775 | |||
| 5790 | ContainerDecl = option("extern" | "packed") | 5776 | ContainerDecl = option("extern" | "packed") |
| 5791 | ("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression))) | 5777 | ("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression))) |
| 5792 | "{" many(ContainerMember) "}"</code></pre> | 5778 | "{" many(ContainerMember) "}"</code></pre> |
example/cat/main.zig+4-4| ... | @@ -5,7 +5,7 @@ const os = std.os; | ... | @@ -5,7 +5,7 @@ const os = std.os; |
| 5 | const warn = std.debug.warn; | 5 | const warn = std.debug.warn; |
| 6 | const allocator = std.debug.global_allocator; | 6 | const allocator = std.debug.global_allocator; |
| 7 | 7 | ||
| 8 | pub fn main() %void { | 8 | pub fn main() !void { |
| 9 | var args_it = os.args(); | 9 | var args_it = os.args(); |
| 10 | const exe = try unwrapArg(??args_it.next(allocator)); | 10 | const exe = try unwrapArg(??args_it.next(allocator)); |
| 11 | var catted_anything = false; | 11 | var catted_anything = false; |
| ... | @@ -36,12 +36,12 @@ pub fn main() %void { | ... | @@ -36,12 +36,12 @@ pub fn main() %void { |
| 36 | } | 36 | } |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | fn usage(exe: []const u8) %void { | 39 | fn usage(exe: []const u8) !void { |
| 40 | warn("Usage: {} [FILE]...\n", exe); | 40 | warn("Usage: {} [FILE]...\n", exe); |
| 41 | return error.Invalid; | 41 | return error.Invalid; |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | fn cat_file(stdout: &io.File, file: &io.File) %void { | 44 | fn cat_file(stdout: &io.File, file: &io.File) !void { |
| 45 | var buf: [1024 * 4]u8 = undefined; | 45 | var buf: [1024 * 4]u8 = undefined; |
| 46 | 46 | ||
| 47 | while (true) { | 47 | while (true) { |
| ... | @@ -61,7 +61,7 @@ fn cat_file(stdout: &io.File, file: &io.File) %void { | ... | @@ -61,7 +61,7 @@ fn cat_file(stdout: &io.File, file: &io.File) %void { |
| 61 | } | 61 | } |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | fn unwrapArg(arg: %[]u8) %[]u8 { | 64 | fn unwrapArg(arg: error![]u8) ![]u8 { |
| 65 | return arg catch |err| { | 65 | return arg catch |err| { |
| 66 | warn("Unable to parse command line: {}\n", err); | 66 | warn("Unable to parse command line: {}\n", err); |
| 67 | return err; | 67 | return err; |
example/guess_number/main.zig+1-1| ... | @@ -5,7 +5,7 @@ const fmt = std.fmt; | ... | @@ -5,7 +5,7 @@ const fmt = std.fmt; |
| 5 | const Rand = std.rand.Rand; | 5 | const Rand = std.rand.Rand; |
| 6 | const os = std.os; | 6 | const os = std.os; |
| 7 | 7 | ||
| 8 | pub fn main() %void { | 8 | pub fn main() !void { |
| 9 | var stdout_file = try io.getStdOut(); | 9 | var stdout_file = try io.getStdOut(); |
| 10 | var stdout_file_stream = io.FileOutStream.init(&stdout_file); | 10 | var stdout_file_stream = io.FileOutStream.init(&stdout_file); |
| 11 | const stdout = &stdout_file_stream.stream; | 11 | const stdout = &stdout_file_stream.stream; |
example/hello_world/hello.zig+1-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | 2 | ||
| 3 | pub fn main() %void { | 3 | pub fn main() !void { |
| 4 | // If this program is run without stdout attached, exit with an error. | 4 | // If this program is run without stdout attached, exit with an error. |
| 5 | var stdout_file = try std.io.getStdOut(); | 5 | var stdout_file = try std.io.getStdOut(); |
| 6 | // If this program encounters pipe failure when printing to stdout, exit | 6 | // If this program encounters pipe failure when printing to stdout, exit |
example/mix_o_files/build.zig+1-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | const Builder = @import("std").build.Builder; | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | ||
| 3 | pub fn build(b: &Builder) %void { | 3 | pub fn build(b: &Builder) void { |
| 4 | const obj = b.addObject("base64", "base64.zig"); | 4 | const obj = b.addObject("base64", "base64.zig"); |
| 5 | 5 | ||
| 6 | const exe = b.addCExecutable("test"); | 6 | const exe = b.addCExecutable("test"); |
example/shared_library/build.zig+1-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | const Builder = @import("std").build.Builder; | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | ||
| 3 | pub fn build(b: &Builder) %void { | 3 | pub fn build(b: &Builder) void { |
| 4 | const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0)); | 4 | const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0)); |
| 5 | 5 | ||
| 6 | const exe = b.addCExecutable("test"); | 6 | const exe = b.addCExecutable("test"); |
src-self-hosted/main.zig+7-11| ... | @@ -14,13 +14,9 @@ const builtin = @import("builtin"); | ... | @@ -14,13 +14,9 @@ const builtin = @import("builtin"); |
| 14 | const ArrayList = std.ArrayList; | 14 | const ArrayList = std.ArrayList; |
| 15 | const c = @import("c.zig"); | 15 | const c = @import("c.zig"); |
| 16 | 16 | ||
| 17 | error InvalidCommandLineArguments; | ||
| 18 | error ZigLibDirNotFound; | ||
| 19 | error ZigInstallationNotFound; | ||
| 20 | |||
| 21 | const default_zig_cache_name = "zig-cache"; | 17 | const default_zig_cache_name = "zig-cache"; |
| 22 | 18 | ||
| 23 | pub fn main() %void { | 19 | pub fn main() !void { |
| 24 | main2() catch |err| { | 20 | main2() catch |err| { |
| 25 | if (err != error.InvalidCommandLineArguments) { | 21 | if (err != error.InvalidCommandLineArguments) { |
| 26 | warn("{}\n", @errorName(err)); | 22 | warn("{}\n", @errorName(err)); |
| ... | @@ -48,7 +44,7 @@ fn badArgs(comptime format: []const u8, args: ...) error { | ... | @@ -48,7 +44,7 @@ fn badArgs(comptime format: []const u8, args: ...) error { |
| 48 | return error.InvalidCommandLineArguments; | 44 | return error.InvalidCommandLineArguments; |
| 49 | } | 45 | } |
| 50 | 46 | ||
| 51 | pub fn main2() %void { | 47 | pub fn main2() !void { |
| 52 | const allocator = std.heap.c_allocator; | 48 | const allocator = std.heap.c_allocator; |
| 53 | 49 | ||
| 54 | const args = try os.argsAlloc(allocator); | 50 | const args = try os.argsAlloc(allocator); |
| ... | @@ -472,7 +468,7 @@ pub fn main2() %void { | ... | @@ -472,7 +468,7 @@ pub fn main2() %void { |
| 472 | } | 468 | } |
| 473 | } | 469 | } |
| 474 | 470 | ||
| 475 | fn printUsage(stream: &io.OutStream) %void { | 471 | fn printUsage(stream: var) !void { |
| 476 | try stream.write( | 472 | try stream.write( |
| 477 | \\Usage: zig [command] [options] | 473 | \\Usage: zig [command] [options] |
| 478 | \\ | 474 | \\ |
| ... | @@ -548,7 +544,7 @@ fn printUsage(stream: &io.OutStream) %void { | ... | @@ -548,7 +544,7 @@ fn printUsage(stream: &io.OutStream) %void { |
| 548 | ); | 544 | ); |
| 549 | } | 545 | } |
| 550 | 546 | ||
| 551 | fn printZen() %void { | 547 | fn printZen() !void { |
| 552 | var stdout_file = try io.getStdErr(); | 548 | var stdout_file = try io.getStdErr(); |
| 553 | try stdout_file.write( | 549 | try stdout_file.write( |
| 554 | \\ | 550 | \\ |
| ... | @@ -569,7 +565,7 @@ fn printZen() %void { | ... | @@ -569,7 +565,7 @@ fn printZen() %void { |
| 569 | } | 565 | } |
| 570 | 566 | ||
| 571 | /// Caller must free result | 567 | /// Caller must free result |
| 572 | fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const u8) %[]u8 { | 568 | fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const u8) ![]u8 { |
| 573 | if (zig_install_prefix_arg) |zig_install_prefix| { | 569 | if (zig_install_prefix_arg) |zig_install_prefix| { |
| 574 | return testZigInstallPrefix(allocator, zig_install_prefix) catch |err| { | 570 | return testZigInstallPrefix(allocator, zig_install_prefix) catch |err| { |
| 575 | warn("No Zig installation found at prefix {}: {}\n", zig_install_prefix_arg, @errorName(err)); | 571 | warn("No Zig installation found at prefix {}: {}\n", zig_install_prefix_arg, @errorName(err)); |
| ... | @@ -585,7 +581,7 @@ fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const | ... | @@ -585,7 +581,7 @@ fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const |
| 585 | } | 581 | } |
| 586 | 582 | ||
| 587 | /// Caller must free result | 583 | /// Caller must free result |
| 588 | fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) %[]u8 { | 584 | fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) ![]u8 { |
| 589 | const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig"); | 585 | const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig"); |
| 590 | errdefer allocator.free(test_zig_dir); | 586 | errdefer allocator.free(test_zig_dir); |
| 591 | 587 | ||
| ... | @@ -599,7 +595,7 @@ fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) %[]u8 | ... | @@ -599,7 +595,7 @@ fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) %[]u8 |
| 599 | } | 595 | } |
| 600 | 596 | ||
| 601 | /// Caller must free result | 597 | /// Caller must free result |
| 602 | fn findZigLibDir(allocator: &mem.Allocator) %[]u8 { | 598 | fn findZigLibDir(allocator: &mem.Allocator) ![]u8 { |
| 603 | const self_exe_path = try os.selfExeDirPath(allocator); | 599 | const self_exe_path = try os.selfExeDirPath(allocator); |
| 604 | defer allocator.free(self_exe_path); | 600 | defer allocator.free(self_exe_path); |
| 605 | 601 |
src-self-hosted/module.zig+6-5| ... | @@ -110,7 +110,7 @@ pub const Module = struct { | ... | @@ -110,7 +110,7 @@ pub const Module = struct { |
| 110 | }; | 110 | }; |
| 111 | 111 | ||
| 112 | pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target, | 112 | pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target, |
| 113 | kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) %&Module | 113 | kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !&Module |
| 114 | { | 114 | { |
| 115 | var name_buffer = try Buffer.init(allocator, name); | 115 | var name_buffer = try Buffer.init(allocator, name); |
| 116 | errdefer name_buffer.deinit(); | 116 | errdefer name_buffer.deinit(); |
| ... | @@ -198,7 +198,7 @@ pub const Module = struct { | ... | @@ -198,7 +198,7 @@ pub const Module = struct { |
| 198 | self.allocator.destroy(self); | 198 | self.allocator.destroy(self); |
| 199 | } | 199 | } |
| 200 | 200 | ||
| 201 | pub fn build(self: &Module) %void { | 201 | pub fn build(self: &Module) !void { |
| 202 | if (self.llvm_argv.len != 0) { | 202 | if (self.llvm_argv.len != 0) { |
| 203 | var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.allocator, | 203 | var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.allocator, |
| 204 | [][]const []const u8 { [][]const u8{"zig (LLVM option parsing)"}, self.llvm_argv, }); | 204 | [][]const []const u8 { [][]const u8{"zig (LLVM option parsing)"}, self.llvm_argv, }); |
| ... | @@ -263,11 +263,12 @@ pub const Module = struct { | ... | @@ -263,11 +263,12 @@ pub const Module = struct { |
| 263 | 263 | ||
| 264 | } | 264 | } |
| 265 | 265 | ||
| 266 | pub fn link(self: &Module, out_file: ?[]const u8) %void { | 266 | pub fn link(self: &Module, out_file: ?[]const u8) !void { |
| 267 | warn("TODO link"); | 267 | warn("TODO link"); |
| 268 | return error.Todo; | ||
| 268 | } | 269 | } |
| 269 | 270 | ||
| 270 | pub fn addLinkLib(self: &Module, name: []const u8, provided_explicitly: bool) %&LinkLib { | 271 | pub fn addLinkLib(self: &Module, name: []const u8, provided_explicitly: bool) !&LinkLib { |
| 271 | const is_libc = mem.eql(u8, name, "c"); | 272 | const is_libc = mem.eql(u8, name, "c"); |
| 272 | 273 | ||
| 273 | if (is_libc) { | 274 | if (is_libc) { |
| ... | @@ -297,7 +298,7 @@ pub const Module = struct { | ... | @@ -297,7 +298,7 @@ pub const Module = struct { |
| 297 | } | 298 | } |
| 298 | }; | 299 | }; |
| 299 | 300 | ||
| 300 | fn printError(comptime format: []const u8, args: ...) %void { | 301 | fn printError(comptime format: []const u8, args: ...) !void { |
| 301 | var stderr_file = try std.io.getStdErr(); | 302 | var stderr_file = try std.io.getStdErr(); |
| 302 | var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file); | 303 | var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file); |
| 303 | const out_stream = &stderr_file_out_stream.stream; | 304 | const out_stream = &stderr_file_out_stream.stream; |
src-self-hosted/parser.zig+22-28| ... | @@ -12,8 +12,6 @@ const io = std.io; | ... | @@ -12,8 +12,6 @@ const io = std.io; |
| 12 | // get rid of this | 12 | // get rid of this |
| 13 | const warn = std.debug.warn; | 13 | const warn = std.debug.warn; |
| 14 | 14 | ||
| 15 | error ParseError; | ||
| 16 | |||
| 17 | pub const Parser = struct { | 15 | pub const Parser = struct { |
| 18 | allocator: &mem.Allocator, | 16 | allocator: &mem.Allocator, |
| 19 | tokenizer: &Tokenizer, | 17 | tokenizer: &Tokenizer, |
| ... | @@ -63,7 +61,7 @@ pub const Parser = struct { | ... | @@ -63,7 +61,7 @@ pub const Parser = struct { |
| 63 | NullableField: &?&ast.Node, | 61 | NullableField: &?&ast.Node, |
| 64 | List: &ArrayList(&ast.Node), | 62 | List: &ArrayList(&ast.Node), |
| 65 | 63 | ||
| 66 | pub fn store(self: &const DestPtr, value: &ast.Node) %void { | 64 | pub fn store(self: &const DestPtr, value: &ast.Node) !void { |
| 67 | switch (*self) { | 65 | switch (*self) { |
| 68 | DestPtr.Field => |ptr| *ptr = value, | 66 | DestPtr.Field => |ptr| *ptr = value, |
| 69 | DestPtr.NullableField => |ptr| *ptr = value, | 67 | DestPtr.NullableField => |ptr| *ptr = value, |
| ... | @@ -99,7 +97,7 @@ pub const Parser = struct { | ... | @@ -99,7 +97,7 @@ pub const Parser = struct { |
| 99 | 97 | ||
| 100 | /// Returns an AST tree, allocated with the parser's allocator. | 98 | /// Returns an AST tree, allocated with the parser's allocator. |
| 101 | /// Result should be freed with `freeAst` when done. | 99 | /// Result should be freed with `freeAst` when done. |
| 102 | pub fn parse(self: &Parser) %Tree { | 100 | pub fn parse(self: &Parser) !Tree { |
| 103 | var stack = self.initUtilityArrayList(State); | 101 | var stack = self.initUtilityArrayList(State); |
| 104 | defer self.deinitUtilityArrayList(stack); | 102 | defer self.deinitUtilityArrayList(stack); |
| 105 | 103 | ||
| ... | @@ -544,7 +542,7 @@ pub const Parser = struct { | ... | @@ -544,7 +542,7 @@ pub const Parser = struct { |
| 544 | } | 542 | } |
| 545 | } | 543 | } |
| 546 | 544 | ||
| 547 | fn createRoot(self: &Parser) %&ast.NodeRoot { | 545 | fn createRoot(self: &Parser) !&ast.NodeRoot { |
| 548 | const node = try self.allocator.create(ast.NodeRoot); | 546 | const node = try self.allocator.create(ast.NodeRoot); |
| 549 | 547 | ||
| 550 | *node = ast.NodeRoot { | 548 | *node = ast.NodeRoot { |
| ... | @@ -555,7 +553,7 @@ pub const Parser = struct { | ... | @@ -555,7 +553,7 @@ pub const Parser = struct { |
| 555 | } | 553 | } |
| 556 | 554 | ||
| 557 | fn createVarDecl(self: &Parser, visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token, | 555 | fn createVarDecl(self: &Parser, visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token, |
| 558 | extern_token: &const ?Token) %&ast.NodeVarDecl | 556 | extern_token: &const ?Token) !&ast.NodeVarDecl |
| 559 | { | 557 | { |
| 560 | const node = try self.allocator.create(ast.NodeVarDecl); | 558 | const node = try self.allocator.create(ast.NodeVarDecl); |
| 561 | 559 | ||
| ... | @@ -577,7 +575,7 @@ pub const Parser = struct { | ... | @@ -577,7 +575,7 @@ pub const Parser = struct { |
| 577 | } | 575 | } |
| 578 | 576 | ||
| 579 | fn createFnProto(self: &Parser, fn_token: &const Token, extern_token: &const ?Token, | 577 | fn createFnProto(self: &Parser, fn_token: &const Token, extern_token: &const ?Token, |
| 580 | cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) %&ast.NodeFnProto | 578 | cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) !&ast.NodeFnProto |
| 581 | { | 579 | { |
| 582 | const node = try self.allocator.create(ast.NodeFnProto); | 580 | const node = try self.allocator.create(ast.NodeFnProto); |
| 583 | 581 | ||
| ... | @@ -599,7 +597,7 @@ pub const Parser = struct { | ... | @@ -599,7 +597,7 @@ pub const Parser = struct { |
| 599 | return node; | 597 | return node; |
| 600 | } | 598 | } |
| 601 | 599 | ||
| 602 | fn createParamDecl(self: &Parser) %&ast.NodeParamDecl { | 600 | fn createParamDecl(self: &Parser) !&ast.NodeParamDecl { |
| 603 | const node = try self.allocator.create(ast.NodeParamDecl); | 601 | const node = try self.allocator.create(ast.NodeParamDecl); |
| 604 | 602 | ||
| 605 | *node = ast.NodeParamDecl { | 603 | *node = ast.NodeParamDecl { |
| ... | @@ -613,7 +611,7 @@ pub const Parser = struct { | ... | @@ -613,7 +611,7 @@ pub const Parser = struct { |
| 613 | return node; | 611 | return node; |
| 614 | } | 612 | } |
| 615 | 613 | ||
| 616 | fn createBlock(self: &Parser, begin_token: &const Token) %&ast.NodeBlock { | 614 | fn createBlock(self: &Parser, begin_token: &const Token) !&ast.NodeBlock { |
| 617 | const node = try self.allocator.create(ast.NodeBlock); | 615 | const node = try self.allocator.create(ast.NodeBlock); |
| 618 | 616 | ||
| 619 | *node = ast.NodeBlock { | 617 | *node = ast.NodeBlock { |
| ... | @@ -625,7 +623,7 @@ pub const Parser = struct { | ... | @@ -625,7 +623,7 @@ pub const Parser = struct { |
| 625 | return node; | 623 | return node; |
| 626 | } | 624 | } |
| 627 | 625 | ||
| 628 | fn createInfixOp(self: &Parser, op_token: &const Token, op: &const ast.NodeInfixOp.InfixOp) %&ast.NodeInfixOp { | 626 | fn createInfixOp(self: &Parser, op_token: &const Token, op: &const ast.NodeInfixOp.InfixOp) !&ast.NodeInfixOp { |
| 629 | const node = try self.allocator.create(ast.NodeInfixOp); | 627 | const node = try self.allocator.create(ast.NodeInfixOp); |
| 630 | 628 | ||
| 631 | *node = ast.NodeInfixOp { | 629 | *node = ast.NodeInfixOp { |
| ... | @@ -638,7 +636,7 @@ pub const Parser = struct { | ... | @@ -638,7 +636,7 @@ pub const Parser = struct { |
| 638 | return node; | 636 | return node; |
| 639 | } | 637 | } |
| 640 | 638 | ||
| 641 | fn createPrefixOp(self: &Parser, op_token: &const Token, op: &const ast.NodePrefixOp.PrefixOp) %&ast.NodePrefixOp { | 639 | fn createPrefixOp(self: &Parser, op_token: &const Token, op: &const ast.NodePrefixOp.PrefixOp) !&ast.NodePrefixOp { |
| 642 | const node = try self.allocator.create(ast.NodePrefixOp); | 640 | const node = try self.allocator.create(ast.NodePrefixOp); |
| 643 | 641 | ||
| 644 | *node = ast.NodePrefixOp { | 642 | *node = ast.NodePrefixOp { |
| ... | @@ -650,7 +648,7 @@ pub const Parser = struct { | ... | @@ -650,7 +648,7 @@ pub const Parser = struct { |
| 650 | return node; | 648 | return node; |
| 651 | } | 649 | } |
| 652 | 650 | ||
| 653 | fn createIdentifier(self: &Parser, name_token: &const Token) %&ast.NodeIdentifier { | 651 | fn createIdentifier(self: &Parser, name_token: &const Token) !&ast.NodeIdentifier { |
| 654 | const node = try self.allocator.create(ast.NodeIdentifier); | 652 | const node = try self.allocator.create(ast.NodeIdentifier); |
| 655 | 653 | ||
| 656 | *node = ast.NodeIdentifier { | 654 | *node = ast.NodeIdentifier { |
| ... | @@ -660,7 +658,7 @@ pub const Parser = struct { | ... | @@ -660,7 +658,7 @@ pub const Parser = struct { |
| 660 | return node; | 658 | return node; |
| 661 | } | 659 | } |
| 662 | 660 | ||
| 663 | fn createIntegerLiteral(self: &Parser, token: &const Token) %&ast.NodeIntegerLiteral { | 661 | fn createIntegerLiteral(self: &Parser, token: &const Token) !&ast.NodeIntegerLiteral { |
| 664 | const node = try self.allocator.create(ast.NodeIntegerLiteral); | 662 | const node = try self.allocator.create(ast.NodeIntegerLiteral); |
| 665 | 663 | ||
| 666 | *node = ast.NodeIntegerLiteral { | 664 | *node = ast.NodeIntegerLiteral { |
| ... | @@ -670,7 +668,7 @@ pub const Parser = struct { | ... | @@ -670,7 +668,7 @@ pub const Parser = struct { |
| 670 | return node; | 668 | return node; |
| 671 | } | 669 | } |
| 672 | 670 | ||
| 673 | fn createFloatLiteral(self: &Parser, token: &const Token) %&ast.NodeFloatLiteral { | 671 | fn createFloatLiteral(self: &Parser, token: &const Token) !&ast.NodeFloatLiteral { |
| 674 | const node = try self.allocator.create(ast.NodeFloatLiteral); | 672 | const node = try self.allocator.create(ast.NodeFloatLiteral); |
| 675 | 673 | ||
| 676 | *node = ast.NodeFloatLiteral { | 674 | *node = ast.NodeFloatLiteral { |
| ... | @@ -680,13 +678,13 @@ pub const Parser = struct { | ... | @@ -680,13 +678,13 @@ pub const Parser = struct { |
| 680 | return node; | 678 | return node; |
| 681 | } | 679 | } |
| 682 | 680 | ||
| 683 | fn createAttachIdentifier(self: &Parser, dest_ptr: &const DestPtr, name_token: &const Token) %&ast.NodeIdentifier { | 681 | fn createAttachIdentifier(self: &Parser, dest_ptr: &const DestPtr, name_token: &const Token) !&ast.NodeIdentifier { |
| 684 | const node = try self.createIdentifier(name_token); | 682 | const node = try self.createIdentifier(name_token); |
| 685 | try dest_ptr.store(&node.base); | 683 | try dest_ptr.store(&node.base); |
| 686 | return node; | 684 | return node; |
| 687 | } | 685 | } |
| 688 | 686 | ||
| 689 | fn createAttachParamDecl(self: &Parser, list: &ArrayList(&ast.Node)) %&ast.NodeParamDecl { | 687 | fn createAttachParamDecl(self: &Parser, list: &ArrayList(&ast.Node)) !&ast.NodeParamDecl { |
| 690 | const node = try self.createParamDecl(); | 688 | const node = try self.createParamDecl(); |
| 691 | try list.append(&node.base); | 689 | try list.append(&node.base); |
| 692 | return node; | 690 | return node; |
| ... | @@ -694,7 +692,7 @@ pub const Parser = struct { | ... | @@ -694,7 +692,7 @@ pub const Parser = struct { |
| 694 | 692 | ||
| 695 | fn createAttachFnProto(self: &Parser, list: &ArrayList(&ast.Node), fn_token: &const Token, | 693 | fn createAttachFnProto(self: &Parser, list: &ArrayList(&ast.Node), fn_token: &const Token, |
| 696 | extern_token: &const ?Token, cc_token: &const ?Token, visib_token: &const ?Token, | 694 | extern_token: &const ?Token, cc_token: &const ?Token, visib_token: &const ?Token, |
| 697 | inline_token: &const ?Token) %&ast.NodeFnProto | 695 | inline_token: &const ?Token) !&ast.NodeFnProto |
| 698 | { | 696 | { |
| 699 | const node = try self.createFnProto(fn_token, extern_token, cc_token, visib_token, inline_token); | 697 | const node = try self.createFnProto(fn_token, extern_token, cc_token, visib_token, inline_token); |
| 700 | try list.append(&node.base); | 698 | try list.append(&node.base); |
| ... | @@ -702,7 +700,7 @@ pub const Parser = struct { | ... | @@ -702,7 +700,7 @@ pub const Parser = struct { |
| 702 | } | 700 | } |
| 703 | 701 | ||
| 704 | fn createAttachVarDecl(self: &Parser, list: &ArrayList(&ast.Node), visib_token: &const ?Token, | 702 | fn createAttachVarDecl(self: &Parser, list: &ArrayList(&ast.Node), visib_token: &const ?Token, |
| 705 | mut_token: &const Token, comptime_token: &const ?Token, extern_token: &const ?Token) %&ast.NodeVarDecl | 703 | mut_token: &const Token, comptime_token: &const ?Token, extern_token: &const ?Token) !&ast.NodeVarDecl |
| 706 | { | 704 | { |
| 707 | const node = try self.createVarDecl(visib_token, mut_token, comptime_token, extern_token); | 705 | const node = try self.createVarDecl(visib_token, mut_token, comptime_token, extern_token); |
| 708 | try list.append(&node.base); | 706 | try list.append(&node.base); |
| ... | @@ -730,13 +728,13 @@ pub const Parser = struct { | ... | @@ -730,13 +728,13 @@ pub const Parser = struct { |
| 730 | return error.ParseError; | 728 | return error.ParseError; |
| 731 | } | 729 | } |
| 732 | 730 | ||
| 733 | fn expectToken(self: &Parser, token: &const Token, id: @TagType(Token.Id)) %void { | 731 | fn expectToken(self: &Parser, token: &const Token, id: @TagType(Token.Id)) !void { |
| 734 | if (token.id != id) { | 732 | if (token.id != id) { |
| 735 | return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id)); | 733 | return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id)); |
| 736 | } | 734 | } |
| 737 | } | 735 | } |
| 738 | 736 | ||
| 739 | fn eatToken(self: &Parser, id: @TagType(Token.Id)) %Token { | 737 | fn eatToken(self: &Parser, id: @TagType(Token.Id)) !Token { |
| 740 | const token = self.getNextToken(); | 738 | const token = self.getNextToken(); |
| 741 | try self.expectToken(token, id); | 739 | try self.expectToken(token, id); |
| 742 | return token; | 740 | return token; |
| ... | @@ -763,7 +761,7 @@ pub const Parser = struct { | ... | @@ -763,7 +761,7 @@ pub const Parser = struct { |
| 763 | indent: usize, | 761 | indent: usize, |
| 764 | }; | 762 | }; |
| 765 | 763 | ||
| 766 | pub fn renderAst(self: &Parser, stream: &std.io.OutStream, root_node: &ast.NodeRoot) %void { | 764 | pub fn renderAst(self: &Parser, stream: var, root_node: &ast.NodeRoot) !void { |
| 767 | var stack = self.initUtilityArrayList(RenderAstFrame); | 765 | var stack = self.initUtilityArrayList(RenderAstFrame); |
| 768 | defer self.deinitUtilityArrayList(stack); | 766 | defer self.deinitUtilityArrayList(stack); |
| 769 | 767 | ||
| ... | @@ -802,7 +800,7 @@ pub const Parser = struct { | ... | @@ -802,7 +800,7 @@ pub const Parser = struct { |
| 802 | Indent: usize, | 800 | Indent: usize, |
| 803 | }; | 801 | }; |
| 804 | 802 | ||
| 805 | pub fn renderSource(self: &Parser, stream: &std.io.OutStream, root_node: &ast.NodeRoot) %void { | 803 | pub fn renderSource(self: &Parser, stream: var, root_node: &ast.NodeRoot) !void { |
| 806 | var stack = self.initUtilityArrayList(RenderState); | 804 | var stack = self.initUtilityArrayList(RenderState); |
| 807 | defer self.deinitUtilityArrayList(stack); | 805 | defer self.deinitUtilityArrayList(stack); |
| 808 | 806 | ||
| ... | @@ -1038,7 +1036,7 @@ pub const Parser = struct { | ... | @@ -1038,7 +1036,7 @@ pub const Parser = struct { |
| 1038 | 1036 | ||
| 1039 | var fixed_buffer_mem: [100 * 1024]u8 = undefined; | 1037 | var fixed_buffer_mem: [100 * 1024]u8 = undefined; |
| 1040 | 1038 | ||
| 1041 | fn testParse(source: []const u8, allocator: &mem.Allocator) %[]u8 { | 1039 | fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 { |
| 1042 | var padded_source: [0x100]u8 = undefined; | 1040 | var padded_source: [0x100]u8 = undefined; |
| 1043 | std.mem.copy(u8, padded_source[0..source.len], source); | 1041 | std.mem.copy(u8, padded_source[0..source.len], source); |
| 1044 | padded_source[source.len + 0] = '\n'; | 1042 | padded_source[source.len + 0] = '\n'; |
| ... | @@ -1058,13 +1056,9 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) %[]u8 { | ... | @@ -1058,13 +1056,9 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) %[]u8 { |
| 1058 | return buffer.toOwnedSlice(); | 1056 | return buffer.toOwnedSlice(); |
| 1059 | } | 1057 | } |
| 1060 | 1058 | ||
| 1061 | error TestFailed; | ||
| 1062 | error NondeterministicMemoryUsage; | ||
| 1063 | error MemoryLeakDetected; | ||
| 1064 | |||
| 1065 | // TODO test for memory leaks | 1059 | // TODO test for memory leaks |
| 1066 | // TODO test for valid frees | 1060 | // TODO test for valid frees |
| 1067 | fn testCanonical(source: []const u8) %void { | 1061 | fn testCanonical(source: []const u8) !void { |
| 1068 | const needed_alloc_count = x: { | 1062 | const needed_alloc_count = x: { |
| 1069 | // Try it once with unlimited memory, make sure it works | 1063 | // Try it once with unlimited memory, make sure it works |
| 1070 | var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]); | 1064 | var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]); |
src/all_types.hpp+47-21| ... | @@ -236,7 +236,7 @@ struct ConstExprValue { | ... | @@ -236,7 +236,7 @@ struct ConstExprValue { |
| 236 | TypeTableEntry *x_type; | 236 | TypeTableEntry *x_type; |
| 237 | ConstExprValue *x_maybe; | 237 | ConstExprValue *x_maybe; |
| 238 | ConstErrValue x_err_union; | 238 | ConstErrValue x_err_union; |
| 239 | ErrorTableEntry *x_pure_err; | 239 | ErrorTableEntry *x_err_set; |
| 240 | BigInt x_enum_tag; | 240 | BigInt x_enum_tag; |
| 241 | ConstStructValue x_struct; | 241 | ConstStructValue x_struct; |
| 242 | ConstUnionValue x_union; | 242 | ConstUnionValue x_union; |
| ... | @@ -353,7 +353,6 @@ enum NodeType { | ... | @@ -353,7 +353,6 @@ enum NodeType { |
| 353 | NodeTypeReturnExpr, | 353 | NodeTypeReturnExpr, |
| 354 | NodeTypeDefer, | 354 | NodeTypeDefer, |
| 355 | NodeTypeVariableDeclaration, | 355 | NodeTypeVariableDeclaration, |
| 356 | NodeTypeErrorValueDecl, | ||
| 357 | NodeTypeTestDecl, | 356 | NodeTypeTestDecl, |
| 358 | NodeTypeBinOpExpr, | 357 | NodeTypeBinOpExpr, |
| 359 | NodeTypeUnwrapErrorExpr, | 358 | NodeTypeUnwrapErrorExpr, |
| ... | @@ -393,6 +392,7 @@ enum NodeType { | ... | @@ -393,6 +392,7 @@ enum NodeType { |
| 393 | NodeTypeVarLiteral, | 392 | NodeTypeVarLiteral, |
| 394 | NodeTypeIfErrorExpr, | 393 | NodeTypeIfErrorExpr, |
| 395 | NodeTypeTestExpr, | 394 | NodeTypeTestExpr, |
| 395 | NodeTypeErrorSetDecl, | ||
| 396 | }; | 396 | }; |
| 397 | 397 | ||
| 398 | struct AstNodeRoot { | 398 | struct AstNodeRoot { |
| ... | @@ -424,6 +424,8 @@ struct AstNodeFnProto { | ... | @@ -424,6 +424,8 @@ struct AstNodeFnProto { |
| 424 | AstNode *align_expr; | 424 | AstNode *align_expr; |
| 425 | // populated if the "section(S)" is present | 425 | // populated if the "section(S)" is present |
| 426 | AstNode *section_expr; | 426 | AstNode *section_expr; |
| 427 | |||
| 428 | bool auto_err_set; | ||
| 427 | }; | 429 | }; |
| 428 | 430 | ||
| 429 | struct AstNodeFnDef { | 431 | struct AstNodeFnDef { |
| ... | @@ -486,12 +488,6 @@ struct AstNodeVariableDeclaration { | ... | @@ -486,12 +488,6 @@ struct AstNodeVariableDeclaration { |
| 486 | AstNode *section_expr; | 488 | AstNode *section_expr; |
| 487 | }; | 489 | }; |
| 488 | 490 | ||
| 489 | struct AstNodeErrorValueDecl { | ||
| 490 | Buf *name; | ||
| 491 | |||
| 492 | ErrorTableEntry *err; | ||
| 493 | }; | ||
| 494 | |||
| 495 | struct AstNodeTestDecl { | 491 | struct AstNodeTestDecl { |
| 496 | Buf *name; | 492 | Buf *name; |
| 497 | 493 | ||
| ... | @@ -514,8 +510,7 @@ enum BinOpType { | ... | @@ -514,8 +510,7 @@ enum BinOpType { |
| 514 | BinOpTypeAssignBitAnd, | 510 | BinOpTypeAssignBitAnd, |
| 515 | BinOpTypeAssignBitXor, | 511 | BinOpTypeAssignBitXor, |
| 516 | BinOpTypeAssignBitOr, | 512 | BinOpTypeAssignBitOr, |
| 517 | BinOpTypeAssignBoolAnd, | 513 | BinOpTypeAssignMergeErrorSets, |
| 518 | BinOpTypeAssignBoolOr, | ||
| 519 | BinOpTypeBoolOr, | 514 | BinOpTypeBoolOr, |
| 520 | BinOpTypeBoolAnd, | 515 | BinOpTypeBoolAnd, |
| 521 | BinOpTypeCmpEq, | 516 | BinOpTypeCmpEq, |
| ... | @@ -540,6 +535,8 @@ enum BinOpType { | ... | @@ -540,6 +535,8 @@ enum BinOpType { |
| 540 | BinOpTypeUnwrapMaybe, | 535 | BinOpTypeUnwrapMaybe, |
| 541 | BinOpTypeArrayCat, | 536 | BinOpTypeArrayCat, |
| 542 | BinOpTypeArrayMult, | 537 | BinOpTypeArrayMult, |
| 538 | BinOpTypeErrorUnion, | ||
| 539 | BinOpTypeMergeErrorSets, | ||
| 543 | }; | 540 | }; |
| 544 | 541 | ||
| 545 | struct AstNodeBinOpExpr { | 542 | struct AstNodeBinOpExpr { |
| ... | @@ -563,6 +560,7 @@ enum CastOp { | ... | @@ -563,6 +560,7 @@ enum CastOp { |
| 563 | CastOpResizeSlice, | 560 | CastOpResizeSlice, |
| 564 | CastOpBytesToSlice, | 561 | CastOpBytesToSlice, |
| 565 | CastOpNumLitToConcrete, | 562 | CastOpNumLitToConcrete, |
| 563 | CastOpErrSet, | ||
| 566 | }; | 564 | }; |
| 567 | 565 | ||
| 568 | struct AstNodeFnCallExpr { | 566 | struct AstNodeFnCallExpr { |
| ... | @@ -595,7 +593,6 @@ enum PrefixOp { | ... | @@ -595,7 +593,6 @@ enum PrefixOp { |
| 595 | PrefixOpNegationWrap, | 593 | PrefixOpNegationWrap, |
| 596 | PrefixOpDereference, | 594 | PrefixOpDereference, |
| 597 | PrefixOpMaybe, | 595 | PrefixOpMaybe, |
| 598 | PrefixOpError, | ||
| 599 | PrefixOpUnwrapMaybe, | 596 | PrefixOpUnwrapMaybe, |
| 600 | }; | 597 | }; |
| 601 | 598 | ||
| ... | @@ -762,6 +759,10 @@ struct AstNodeContainerDecl { | ... | @@ -762,6 +759,10 @@ struct AstNodeContainerDecl { |
| 762 | bool auto_enum; // union(enum) | 759 | bool auto_enum; // union(enum) |
| 763 | }; | 760 | }; |
| 764 | 761 | ||
| 762 | struct AstNodeErrorSetDecl { | ||
| 763 | ZigList<AstNode *> decls; | ||
| 764 | }; | ||
| 765 | |||
| 765 | struct AstNodeStructField { | 766 | struct AstNodeStructField { |
| 766 | VisibMod visib_mod; | 767 | VisibMod visib_mod; |
| 767 | Buf *name; | 768 | Buf *name; |
| ... | @@ -858,7 +859,6 @@ struct AstNode { | ... | @@ -858,7 +859,6 @@ struct AstNode { |
| 858 | AstNodeReturnExpr return_expr; | 859 | AstNodeReturnExpr return_expr; |
| 859 | AstNodeDefer defer; | 860 | AstNodeDefer defer; |
| 860 | AstNodeVariableDeclaration variable_declaration; | 861 | AstNodeVariableDeclaration variable_declaration; |
| 861 | AstNodeErrorValueDecl error_value_decl; | ||
| 862 | AstNodeTestDecl test_decl; | 862 | AstNodeTestDecl test_decl; |
| 863 | AstNodeBinOpExpr bin_op_expr; | 863 | AstNodeBinOpExpr bin_op_expr; |
| 864 | AstNodeCatchExpr unwrap_err_expr; | 864 | AstNodeCatchExpr unwrap_err_expr; |
| ... | @@ -899,6 +899,7 @@ struct AstNode { | ... | @@ -899,6 +899,7 @@ struct AstNode { |
| 899 | AstNodeArrayType array_type; | 899 | AstNodeArrayType array_type; |
| 900 | AstNodeErrorType error_type; | 900 | AstNodeErrorType error_type; |
| 901 | AstNodeVarLiteral var_literal; | 901 | AstNodeVarLiteral var_literal; |
| 902 | AstNodeErrorSetDecl err_set_decl; | ||
| 902 | } data; | 903 | } data; |
| 903 | }; | 904 | }; |
| 904 | 905 | ||
| ... | @@ -993,8 +994,15 @@ struct TypeTableEntryMaybe { | ... | @@ -993,8 +994,15 @@ struct TypeTableEntryMaybe { |
| 993 | TypeTableEntry *child_type; | 994 | TypeTableEntry *child_type; |
| 994 | }; | 995 | }; |
| 995 | 996 | ||
| 996 | struct TypeTableEntryError { | 997 | struct TypeTableEntryErrorUnion { |
| 997 | TypeTableEntry *child_type; | 998 | TypeTableEntry *err_set_type; |
| 999 | TypeTableEntry *payload_type; | ||
| 1000 | }; | ||
| 1001 | |||
| 1002 | struct TypeTableEntryErrorSet { | ||
| 1003 | uint32_t err_count; | ||
| 1004 | ErrorTableEntry **errors; | ||
| 1005 | FnTableEntry *infer_fn; | ||
| 998 | }; | 1006 | }; |
| 999 | 1007 | ||
| 1000 | struct TypeTableEntryEnum { | 1008 | struct TypeTableEntryEnum { |
| ... | @@ -1097,7 +1105,7 @@ enum TypeTableEntryId { | ... | @@ -1097,7 +1105,7 @@ enum TypeTableEntryId { |
| 1097 | TypeTableEntryIdNullLit, | 1105 | TypeTableEntryIdNullLit, |
| 1098 | TypeTableEntryIdMaybe, | 1106 | TypeTableEntryIdMaybe, |
| 1099 | TypeTableEntryIdErrorUnion, | 1107 | TypeTableEntryIdErrorUnion, |
| 1100 | TypeTableEntryIdPureError, | 1108 | TypeTableEntryIdErrorSet, |
| 1101 | TypeTableEntryIdEnum, | 1109 | TypeTableEntryIdEnum, |
| 1102 | TypeTableEntryIdUnion, | 1110 | TypeTableEntryIdUnion, |
| 1103 | TypeTableEntryIdFn, | 1111 | TypeTableEntryIdFn, |
| ... | @@ -1126,7 +1134,8 @@ struct TypeTableEntry { | ... | @@ -1126,7 +1134,8 @@ struct TypeTableEntry { |
| 1126 | TypeTableEntryArray array; | 1134 | TypeTableEntryArray array; |
| 1127 | TypeTableEntryStruct structure; | 1135 | TypeTableEntryStruct structure; |
| 1128 | TypeTableEntryMaybe maybe; | 1136 | TypeTableEntryMaybe maybe; |
| 1129 | TypeTableEntryError error; | 1137 | TypeTableEntryErrorUnion error_union; |
| 1138 | TypeTableEntryErrorSet error_set; | ||
| 1130 | TypeTableEntryEnum enumeration; | 1139 | TypeTableEntryEnum enumeration; |
| 1131 | TypeTableEntryUnion unionation; | 1140 | TypeTableEntryUnion unionation; |
| 1132 | TypeTableEntryFn fn; | 1141 | TypeTableEntryFn fn; |
| ... | @@ -1136,7 +1145,6 @@ struct TypeTableEntry { | ... | @@ -1136,7 +1145,6 @@ struct TypeTableEntry { |
| 1136 | // use these fields to make sure we don't duplicate type table entries for the same type | 1145 | // use these fields to make sure we don't duplicate type table entries for the same type |
| 1137 | TypeTableEntry *pointer_parent[2]; // [0 - mut, 1 - const] | 1146 | TypeTableEntry *pointer_parent[2]; // [0 - mut, 1 - const] |
| 1138 | TypeTableEntry *maybe_parent; | 1147 | TypeTableEntry *maybe_parent; |
| 1139 | TypeTableEntry *error_parent; | ||
| 1140 | // If we generate a constant name value for this type, we memoize it here. | 1148 | // If we generate a constant name value for this type, we memoize it here. |
| 1141 | // The type of this is array | 1149 | // The type of this is array |
| 1142 | ConstExprValue *cached_const_name_val; | 1150 | ConstExprValue *cached_const_name_val; |
| ... | @@ -1340,6 +1348,10 @@ struct TypeId { | ... | @@ -1340,6 +1348,10 @@ struct TypeId { |
| 1340 | bool is_signed; | 1348 | bool is_signed; |
| 1341 | uint32_t bit_count; | 1349 | uint32_t bit_count; |
| 1342 | } integer; | 1350 | } integer; |
| 1351 | struct { | ||
| 1352 | TypeTableEntry *err_set_type; | ||
| 1353 | TypeTableEntry *payload_type; | ||
| 1354 | } error_union; | ||
| 1343 | } data; | 1355 | } data; |
| 1344 | }; | 1356 | }; |
| 1345 | 1357 | ||
| ... | @@ -1481,7 +1493,7 @@ struct CodeGen { | ... | @@ -1481,7 +1493,7 @@ struct CodeGen { |
| 1481 | TypeTableEntry *entry_undef; | 1493 | TypeTableEntry *entry_undef; |
| 1482 | TypeTableEntry *entry_null; | 1494 | TypeTableEntry *entry_null; |
| 1483 | TypeTableEntry *entry_var; | 1495 | TypeTableEntry *entry_var; |
| 1484 | TypeTableEntry *entry_pure_error; | 1496 | TypeTableEntry *entry_global_error_set; |
| 1485 | TypeTableEntry *entry_arg_tuple; | 1497 | TypeTableEntry *entry_arg_tuple; |
| 1486 | } builtin_types; | 1498 | } builtin_types; |
| 1487 | 1499 | ||
| ... | @@ -1570,7 +1582,6 @@ struct CodeGen { | ... | @@ -1570,7 +1582,6 @@ struct CodeGen { |
| 1570 | LLVMValueRef return_address_fn_val; | 1582 | LLVMValueRef return_address_fn_val; |
| 1571 | LLVMValueRef frame_address_fn_val; | 1583 | LLVMValueRef frame_address_fn_val; |
| 1572 | bool error_during_imports; | 1584 | bool error_during_imports; |
| 1573 | TypeTableEntry *err_tag_type; | ||
| 1574 | 1585 | ||
| 1575 | const char **clang_argv; | 1586 | const char **clang_argv; |
| 1576 | size_t clang_argv_len; | 1587 | size_t clang_argv_len; |
| ... | @@ -1584,7 +1595,9 @@ struct CodeGen { | ... | @@ -1584,7 +1595,9 @@ struct CodeGen { |
| 1584 | 1595 | ||
| 1585 | bool each_lib_rpath; | 1596 | bool each_lib_rpath; |
| 1586 | 1597 | ||
| 1587 | ZigList<AstNode *> error_decls; | 1598 | TypeTableEntry *err_tag_type; |
| 1599 | ZigList<ZigLLVMDIEnumerator *> err_enumerators; | ||
| 1600 | ZigList<ErrorTableEntry *> errors_by_index; | ||
| 1588 | bool generate_error_name_table; | 1601 | bool generate_error_name_table; |
| 1589 | LLVMValueRef err_name_table; | 1602 | LLVMValueRef err_name_table; |
| 1590 | size_t largest_err_name_len; | 1603 | size_t largest_err_name_len; |
| ... | @@ -1617,6 +1630,10 @@ struct CodeGen { | ... | @@ -1617,6 +1630,10 @@ struct CodeGen { |
| 1617 | TypeTableEntry *align_amt_type; | 1630 | TypeTableEntry *align_amt_type; |
| 1618 | TypeTableEntry *stack_trace_type; | 1631 | TypeTableEntry *stack_trace_type; |
| 1619 | TypeTableEntry *ptr_to_stack_trace_type; | 1632 | TypeTableEntry *ptr_to_stack_trace_type; |
| 1633 | |||
| 1634 | ZigList<ZigLLVMDIType **> error_di_types; | ||
| 1635 | |||
| 1636 | ZigList<Buf *> forbidden_libs; | ||
| 1620 | }; | 1637 | }; |
| 1621 | 1638 | ||
| 1622 | enum VarLinkage { | 1639 | enum VarLinkage { |
| ... | @@ -1653,6 +1670,7 @@ struct ErrorTableEntry { | ... | @@ -1653,6 +1670,7 @@ struct ErrorTableEntry { |
| 1653 | Buf name; | 1670 | Buf name; |
| 1654 | uint32_t value; | 1671 | uint32_t value; |
| 1655 | AstNode *decl_node; | 1672 | AstNode *decl_node; |
| 1673 | TypeTableEntry *set_with_only_this_in_it; | ||
| 1656 | // If we generate a constant error name value for this error, we memoize it here. | 1674 | // If we generate a constant error name value for this error, we memoize it here. |
| 1657 | // The type of this is array | 1675 | // The type of this is array |
| 1658 | ConstExprValue *cached_error_name_val; | 1676 | ConstExprValue *cached_error_name_val; |
| ... | @@ -1920,6 +1938,7 @@ enum IrInstructionId { | ... | @@ -1920,6 +1938,7 @@ enum IrInstructionId { |
| 1920 | IrInstructionIdArgType, | 1938 | IrInstructionIdArgType, |
| 1921 | IrInstructionIdExport, | 1939 | IrInstructionIdExport, |
| 1922 | IrInstructionIdErrorReturnTrace, | 1940 | IrInstructionIdErrorReturnTrace, |
| 1941 | IrInstructionIdErrorUnion, | ||
| 1923 | }; | 1942 | }; |
| 1924 | 1943 | ||
| 1925 | struct IrInstruction { | 1944 | struct IrInstruction { |
| ... | @@ -1996,7 +2015,6 @@ enum IrUnOp { | ... | @@ -1996,7 +2015,6 @@ enum IrUnOp { |
| 1996 | IrUnOpNegation, | 2015 | IrUnOpNegation, |
| 1997 | IrUnOpNegationWrap, | 2016 | IrUnOpNegationWrap, |
| 1998 | IrUnOpDereference, | 2017 | IrUnOpDereference, |
| 1999 | IrUnOpError, | ||
| 2000 | IrUnOpMaybe, | 2018 | IrUnOpMaybe, |
| 2001 | }; | 2019 | }; |
| 2002 | 2020 | ||
| ... | @@ -2039,6 +2057,7 @@ enum IrBinOp { | ... | @@ -2039,6 +2057,7 @@ enum IrBinOp { |
| 2039 | IrBinOpRemMod, | 2057 | IrBinOpRemMod, |
| 2040 | IrBinOpArrayCat, | 2058 | IrBinOpArrayCat, |
| 2041 | IrBinOpArrayMult, | 2059 | IrBinOpArrayMult, |
| 2060 | IrBinOpMergeErrorSets, | ||
| 2042 | }; | 2061 | }; |
| 2043 | 2062 | ||
| 2044 | struct IrInstructionBinOp { | 2063 | struct IrInstructionBinOp { |
| ... | @@ -2750,6 +2769,13 @@ struct IrInstructionErrorReturnTrace { | ... | @@ -2750,6 +2769,13 @@ struct IrInstructionErrorReturnTrace { |
| 2750 | IrInstruction base; | 2769 | IrInstruction base; |
| 2751 | }; | 2770 | }; |
| 2752 | 2771 | ||
| 2772 | struct IrInstructionErrorUnion { | ||
| 2773 | IrInstruction base; | ||
| 2774 | |||
| 2775 | IrInstruction *err_set; | ||
| 2776 | IrInstruction *payload; | ||
| 2777 | }; | ||
| 2778 | |||
| 2753 | static const size_t slice_ptr_index = 0; | 2779 | static const size_t slice_ptr_index = 0; |
| 2754 | static const size_t slice_len_index = 1; | 2780 | static const size_t slice_len_index = 1; |
| 2755 | 2781 |
src/analyze.cpp+169-201| ... | @@ -224,7 +224,7 @@ bool type_is_complete(TypeTableEntry *type_entry) { | ... | @@ -224,7 +224,7 @@ bool type_is_complete(TypeTableEntry *type_entry) { |
| 224 | case TypeTableEntryIdNullLit: | 224 | case TypeTableEntryIdNullLit: |
| 225 | case TypeTableEntryIdMaybe: | 225 | case TypeTableEntryIdMaybe: |
| 226 | case TypeTableEntryIdErrorUnion: | 226 | case TypeTableEntryIdErrorUnion: |
| 227 | case TypeTableEntryIdPureError: | 227 | case TypeTableEntryIdErrorSet: |
| 228 | case TypeTableEntryIdFn: | 228 | case TypeTableEntryIdFn: |
| 229 | case TypeTableEntryIdNamespace: | 229 | case TypeTableEntryIdNamespace: |
| 230 | case TypeTableEntryIdBlock: | 230 | case TypeTableEntryIdBlock: |
| ... | @@ -260,7 +260,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) { | ... | @@ -260,7 +260,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) { |
| 260 | case TypeTableEntryIdNullLit: | 260 | case TypeTableEntryIdNullLit: |
| 261 | case TypeTableEntryIdMaybe: | 261 | case TypeTableEntryIdMaybe: |
| 262 | case TypeTableEntryIdErrorUnion: | 262 | case TypeTableEntryIdErrorUnion: |
| 263 | case TypeTableEntryIdPureError: | 263 | case TypeTableEntryIdErrorSet: |
| 264 | case TypeTableEntryIdFn: | 264 | case TypeTableEntryIdFn: |
| 265 | case TypeTableEntryIdNamespace: | 265 | case TypeTableEntryIdNamespace: |
| 266 | case TypeTableEntryIdBlock: | 266 | case TypeTableEntryIdBlock: |
| ... | @@ -514,29 +514,47 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) { | ... | @@ -514,29 +514,47 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) { |
| 514 | } | 514 | } |
| 515 | } | 515 | } |
| 516 | 516 | ||
| 517 | TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) { | 517 | TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, TypeTableEntry *payload_type) { |
| 518 | if (child_type->error_parent) | 518 | assert(err_set_type->id == TypeTableEntryIdErrorSet); |
| 519 | return child_type->error_parent; | 519 | assert(!type_is_invalid(payload_type)); |
| 520 | |||
| 521 | TypeId type_id = {}; | ||
| 522 | type_id.id = TypeTableEntryIdErrorUnion; | ||
| 523 | type_id.data.error_union.err_set_type = err_set_type; | ||
| 524 | type_id.data.error_union.payload_type = payload_type; | ||
| 525 | |||
| 526 | auto existing_entry = g->type_table.maybe_get(type_id); | ||
| 527 | if (existing_entry) { | ||
| 528 | return existing_entry->value; | ||
| 529 | } | ||
| 520 | 530 | ||
| 521 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion); | 531 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion); |
| 522 | entry->is_copyable = true; | 532 | entry->is_copyable = true; |
| 523 | assert(child_type->type_ref); | 533 | assert(payload_type->di_type); |
| 524 | assert(child_type->di_type); | 534 | ensure_complete_type(g, payload_type); |
| 525 | ensure_complete_type(g, child_type); | ||
| 526 | 535 | ||
| 527 | buf_resize(&entry->name, 0); | 536 | buf_resize(&entry->name, 0); |
| 528 | buf_appendf(&entry->name, "%%%s", buf_ptr(&child_type->name)); | 537 | buf_appendf(&entry->name, "%s!%s", buf_ptr(&err_set_type->name), buf_ptr(&payload_type->name)); |
| 529 | 538 | ||
| 530 | entry->data.error.child_type = child_type; | 539 | entry->data.error_union.err_set_type = err_set_type; |
| 531 | 540 | entry->data.error_union.payload_type = payload_type; | |
| 532 | if (!type_has_bits(child_type)) { | ||
| 533 | entry->type_ref = g->err_tag_type->type_ref; | ||
| 534 | entry->di_type = g->err_tag_type->di_type; | ||
| 535 | 541 | ||
| 542 | if (!type_has_bits(payload_type)) { | ||
| 543 | if (type_has_bits(err_set_type)) { | ||
| 544 | entry->type_ref = err_set_type->type_ref; | ||
| 545 | entry->di_type = err_set_type->di_type; | ||
| 546 | g->error_di_types.append(&entry->di_type); | ||
| 547 | } else { | ||
| 548 | entry->zero_bits = true; | ||
| 549 | entry->di_type = g->builtin_types.entry_void->di_type; | ||
| 550 | } | ||
| 551 | } else if (!type_has_bits(err_set_type)) { | ||
| 552 | entry->type_ref = payload_type->type_ref; | ||
| 553 | entry->di_type = payload_type->di_type; | ||
| 536 | } else { | 554 | } else { |
| 537 | LLVMTypeRef elem_types[] = { | 555 | LLVMTypeRef elem_types[] = { |
| 538 | g->err_tag_type->type_ref, | 556 | err_set_type->type_ref, |
| 539 | child_type->type_ref, | 557 | payload_type->type_ref, |
| 540 | }; | 558 | }; |
| 541 | entry->type_ref = LLVMStructType(elem_types, 2, false); | 559 | entry->type_ref = LLVMStructType(elem_types, 2, false); |
| 542 | 560 | ||
| ... | @@ -547,12 +565,12 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) { | ... | @@ -547,12 +565,12 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) { |
| 547 | ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name), | 565 | ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name), |
| 548 | compile_unit_scope, di_file, line); | 566 | compile_unit_scope, di_file, line); |
| 549 | 567 | ||
| 550 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, g->err_tag_type->type_ref); | 568 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, err_set_type->type_ref); |
| 551 | uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, g->err_tag_type->type_ref); | 569 | uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, err_set_type->type_ref); |
| 552 | uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, err_union_err_index); | 570 | uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, err_union_err_index); |
| 553 | 571 | ||
| 554 | uint64_t value_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, child_type->type_ref); | 572 | uint64_t value_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, payload_type->type_ref); |
| 555 | uint64_t value_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, child_type->type_ref); | 573 | uint64_t value_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, payload_type->type_ref); |
| 556 | uint64_t value_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, | 574 | uint64_t value_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, |
| 557 | err_union_payload_index); | 575 | err_union_payload_index); |
| 558 | 576 | ||
| ... | @@ -565,13 +583,13 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) { | ... | @@ -565,13 +583,13 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) { |
| 565 | tag_debug_size_in_bits, | 583 | tag_debug_size_in_bits, |
| 566 | tag_debug_align_in_bits, | 584 | tag_debug_align_in_bits, |
| 567 | tag_offset_in_bits, | 585 | tag_offset_in_bits, |
| 568 | 0, child_type->di_type), | 586 | 0, err_set_type->di_type), |
| 569 | ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type), | 587 | ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type), |
| 570 | "value", di_file, line, | 588 | "value", di_file, line, |
| 571 | value_debug_size_in_bits, | 589 | value_debug_size_in_bits, |
| 572 | value_debug_align_in_bits, | 590 | value_debug_align_in_bits, |
| 573 | value_offset_in_bits, | 591 | value_offset_in_bits, |
| 574 | 0, child_type->di_type), | 592 | 0, payload_type->di_type), |
| 575 | }; | 593 | }; |
| 576 | 594 | ||
| 577 | ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, | 595 | ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, |
| ... | @@ -587,7 +605,7 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) { | ... | @@ -587,7 +605,7 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) { |
| 587 | entry->di_type = replacement_di_type; | 605 | entry->di_type = replacement_di_type; |
| 588 | } | 606 | } |
| 589 | 607 | ||
| 590 | child_type->error_parent = entry; | 608 | g->type_table.put(type_id, entry); |
| 591 | return entry; | 609 | return entry; |
| 592 | } | 610 | } |
| 593 | 611 | ||
| ... | @@ -937,7 +955,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { | ... | @@ -937,7 +955,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 937 | handle_is_ptr(fn_type_id->return_type); | 955 | handle_is_ptr(fn_type_id->return_type); |
| 938 | bool prefix_arg_error_return_trace = g->have_err_ret_tracing && | 956 | bool prefix_arg_error_return_trace = g->have_err_ret_tracing && |
| 939 | (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion || | 957 | (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion || |
| 940 | fn_type_id->return_type->id == TypeTableEntryIdPureError); | 958 | fn_type_id->return_type->id == TypeTableEntryIdErrorSet); |
| 941 | // +1 for maybe making the first argument the return value | 959 | // +1 for maybe making the first argument the return value |
| 942 | // +1 for maybe last argument the error return trace | 960 | // +1 for maybe last argument the error return trace |
| 943 | LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(2 + fn_type_id->param_count); | 961 | LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(2 + fn_type_id->param_count); |
| ... | @@ -1177,7 +1195,7 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) { | ... | @@ -1177,7 +1195,7 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) { |
| 1177 | case TypeTableEntryIdUndefLit: | 1195 | case TypeTableEntryIdUndefLit: |
| 1178 | case TypeTableEntryIdNullLit: | 1196 | case TypeTableEntryIdNullLit: |
| 1179 | case TypeTableEntryIdErrorUnion: | 1197 | case TypeTableEntryIdErrorUnion: |
| 1180 | case TypeTableEntryIdPureError: | 1198 | case TypeTableEntryIdErrorSet: |
| 1181 | case TypeTableEntryIdNamespace: | 1199 | case TypeTableEntryIdNamespace: |
| 1182 | case TypeTableEntryIdBlock: | 1200 | case TypeTableEntryIdBlock: |
| 1183 | case TypeTableEntryIdBoundFn: | 1201 | case TypeTableEntryIdBoundFn: |
| ... | @@ -1218,7 +1236,7 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) { | ... | @@ -1218,7 +1236,7 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) { |
| 1218 | case TypeTableEntryIdUndefLit: | 1236 | case TypeTableEntryIdUndefLit: |
| 1219 | case TypeTableEntryIdNullLit: | 1237 | case TypeTableEntryIdNullLit: |
| 1220 | case TypeTableEntryIdErrorUnion: | 1238 | case TypeTableEntryIdErrorUnion: |
| 1221 | case TypeTableEntryIdPureError: | 1239 | case TypeTableEntryIdErrorSet: |
| 1222 | case TypeTableEntryIdNamespace: | 1240 | case TypeTableEntryIdNamespace: |
| 1223 | case TypeTableEntryIdBlock: | 1241 | case TypeTableEntryIdBlock: |
| 1224 | case TypeTableEntryIdBoundFn: | 1242 | case TypeTableEntryIdBoundFn: |
| ... | @@ -1263,7 +1281,23 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) { | ... | @@ -1263,7 +1281,23 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) { |
| 1263 | zig_unreachable(); | 1281 | zig_unreachable(); |
| 1264 | } | 1282 | } |
| 1265 | 1283 | ||
| 1266 | static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope) { | 1284 | TypeTableEntry *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 | |||
| 1300 | static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope, FnTableEntry *fn_entry) { | ||
| 1267 | assert(proto_node->type == NodeTypeFnProto); | 1301 | assert(proto_node->type == NodeTypeFnProto); |
| 1268 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; | 1302 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| 1269 | 1303 | ||
| ... | @@ -1359,7 +1393,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c | ... | @@ -1359,7 +1393,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 1359 | case TypeTableEntryIdStruct: | 1393 | case TypeTableEntryIdStruct: |
| 1360 | case TypeTableEntryIdMaybe: | 1394 | case TypeTableEntryIdMaybe: |
| 1361 | case TypeTableEntryIdErrorUnion: | 1395 | case TypeTableEntryIdErrorUnion: |
| 1362 | case TypeTableEntryIdPureError: | 1396 | case TypeTableEntryIdErrorSet: |
| 1363 | case TypeTableEntryIdEnum: | 1397 | case TypeTableEntryIdEnum: |
| 1364 | case TypeTableEntryIdUnion: | 1398 | case TypeTableEntryIdUnion: |
| 1365 | case TypeTableEntryIdFn: | 1399 | case TypeTableEntryIdFn: |
| ... | @@ -1382,13 +1416,19 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c | ... | @@ -1382,13 +1416,19 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 1382 | } | 1416 | } |
| 1383 | } | 1417 | } |
| 1384 | 1418 | ||
| 1385 | fn_type_id.return_type = (fn_proto->return_type == nullptr) ? | 1419 | TypeTableEntry *specified_return_type = analyze_type_expr(g, child_scope, fn_proto->return_type); |
| 1386 | g->builtin_types.entry_void : analyze_type_expr(g, child_scope, fn_proto->return_type); | 1420 | if (type_is_invalid(specified_return_type)) { |
| 1387 | 1421 | fn_type_id.return_type = g->builtin_types.entry_invalid; | |
| 1388 | if (type_is_invalid(fn_type_id.return_type)) { | ||
| 1389 | return g->builtin_types.entry_invalid; | 1422 | return g->builtin_types.entry_invalid; |
| 1390 | } | 1423 | } |
| 1391 | 1424 | ||
| 1425 | if (fn_proto->auto_err_set) { | ||
| 1426 | TypeTableEntry *inferred_err_set_type = get_auto_err_set_type(g, fn_entry); | ||
| 1427 | fn_type_id.return_type = get_error_union_type(g, inferred_err_set_type, specified_return_type); | ||
| 1428 | } else { | ||
| 1429 | fn_type_id.return_type = specified_return_type; | ||
| 1430 | } | ||
| 1431 | |||
| 1392 | if (fn_type_id.cc != CallingConventionUnspecified && !type_allowed_in_extern(g, fn_type_id.return_type)) { | 1432 | if (fn_type_id.cc != CallingConventionUnspecified && !type_allowed_in_extern(g, fn_type_id.return_type)) { |
| 1393 | add_node_error(g, fn_proto->return_type, | 1433 | add_node_error(g, fn_proto->return_type, |
| 1394 | buf_sprintf("return type '%s' not allowed in function with calling convention '%s'", | 1434 | buf_sprintf("return type '%s' not allowed in function with calling convention '%s'", |
| ... | @@ -1434,7 +1474,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c | ... | @@ -1434,7 +1474,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 1434 | case TypeTableEntryIdStruct: | 1474 | case TypeTableEntryIdStruct: |
| 1435 | case TypeTableEntryIdMaybe: | 1475 | case TypeTableEntryIdMaybe: |
| 1436 | case TypeTableEntryIdErrorUnion: | 1476 | case TypeTableEntryIdErrorUnion: |
| 1437 | case TypeTableEntryIdPureError: | 1477 | case TypeTableEntryIdErrorSet: |
| 1438 | case TypeTableEntryIdEnum: | 1478 | case TypeTableEntryIdEnum: |
| 1439 | case TypeTableEntryIdUnion: | 1479 | case TypeTableEntryIdUnion: |
| 1440 | case TypeTableEntryIdFn: | 1480 | case TypeTableEntryIdFn: |
| ... | @@ -2756,7 +2796,8 @@ TypeTableEntry *get_test_fn_type(CodeGen *g) { | ... | @@ -2756,7 +2796,8 @@ TypeTableEntry *get_test_fn_type(CodeGen *g) { |
| 2756 | return g->test_fn_type; | 2796 | return g->test_fn_type; |
| 2757 | 2797 | ||
| 2758 | FnTypeId fn_type_id = {0}; | 2798 | FnTypeId fn_type_id = {0}; |
| 2759 | fn_type_id.return_type = get_error_type(g, g->builtin_types.entry_void); | 2799 | fn_type_id.return_type = get_error_union_type(g, g->builtin_types.entry_global_error_set, |
| 2800 | g->builtin_types.entry_void); | ||
| 2760 | g->test_fn_type = get_fn_type(g, &fn_type_id); | 2801 | g->test_fn_type = get_fn_type(g, &fn_type_id); |
| 2761 | return g->test_fn_type; | 2802 | return g->test_fn_type; |
| 2762 | } | 2803 | } |
| ... | @@ -2824,7 +2865,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { | ... | @@ -2824,7 +2865,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 2824 | 2865 | ||
| 2825 | Scope *child_scope = fn_table_entry->fndef_scope ? &fn_table_entry->fndef_scope->base : tld_fn->base.parent_scope; | 2866 | Scope *child_scope = fn_table_entry->fndef_scope ? &fn_table_entry->fndef_scope->base : tld_fn->base.parent_scope; |
| 2826 | 2867 | ||
| 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); |
| 2828 | 2869 | ||
| 2829 | if (fn_proto->section_expr != nullptr) { | 2870 | if (fn_proto->section_expr != nullptr) { |
| 2830 | if (fn_table_entry->body_node == nullptr) { | 2871 | if (fn_table_entry->body_node == nullptr) { |
| ... | @@ -2949,29 +2990,6 @@ static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope | ... | @@ -2949,29 +2990,6 @@ static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope |
| 2949 | g->resolve_queue.append(&tld_fn->base); | 2990 | g->resolve_queue.append(&tld_fn->base); |
| 2950 | } | 2991 | } |
| 2951 | 2992 | ||
| 2952 | static 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 | |||
| 2975 | static void preview_comptime_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) { | 2993 | static void preview_comptime_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) { |
| 2976 | assert(node->type == NodeTypeCompTime); | 2994 | assert(node->type == NodeTypeCompTime); |
| 2977 | 2995 | ||
| ... | @@ -3045,10 +3063,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { | ... | @@ -3045,10 +3063,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 3045 | import->use_decls.append(node); | 3063 | import->use_decls.append(node); |
| 3046 | break; | 3064 | break; |
| 3047 | } | 3065 | } |
| 3048 | case NodeTypeErrorValueDecl: | ||
| 3049 | // error value declarations do not depend on other top level decls | ||
| 3050 | preview_error_value_decl(g, node); | ||
| 3051 | break; | ||
| 3052 | case NodeTypeTestDecl: | 3066 | case NodeTypeTestDecl: |
| 3053 | preview_test_decl(g, node, decls_scope); | 3067 | preview_test_decl(g, node, decls_scope); |
| 3054 | break; | 3068 | break; |
| ... | @@ -3097,6 +3111,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { | ... | @@ -3097,6 +3111,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 3097 | case NodeTypeVarLiteral: | 3111 | case NodeTypeVarLiteral: |
| 3098 | case NodeTypeIfErrorExpr: | 3112 | case NodeTypeIfErrorExpr: |
| 3099 | case NodeTypeTestExpr: | 3113 | case NodeTypeTestExpr: |
| 3114 | case NodeTypeErrorSetDecl: | ||
| 3100 | zig_unreachable(); | 3115 | zig_unreachable(); |
| 3101 | } | 3116 | } |
| 3102 | } | 3117 | } |
| ... | @@ -3147,7 +3162,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt | ... | @@ -3147,7 +3162,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt |
| 3147 | case TypeTableEntryIdStruct: | 3162 | case TypeTableEntryIdStruct: |
| 3148 | case TypeTableEntryIdMaybe: | 3163 | case TypeTableEntryIdMaybe: |
| 3149 | case TypeTableEntryIdErrorUnion: | 3164 | case TypeTableEntryIdErrorUnion: |
| 3150 | case TypeTableEntryIdPureError: | 3165 | case TypeTableEntryIdErrorSet: |
| 3151 | case TypeTableEntryIdEnum: | 3166 | case TypeTableEntryIdEnum: |
| 3152 | case TypeTableEntryIdUnion: | 3167 | case TypeTableEntryIdUnion: |
| 3153 | case TypeTableEntryIdFn: | 3168 | case TypeTableEntryIdFn: |
| ... | @@ -3362,108 +3377,6 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *so | ... | @@ -3362,108 +3377,6 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *so |
| 3362 | g->tld_ref_source_node_stack.pop(); | 3377 | g->tld_ref_source_node_stack.pop(); |
| 3363 | } | 3378 | } |
| 3364 | 3379 | ||
| 3365 | bool 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 | |||
| 3467 | Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) { | 3380 | Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) { |
| 3468 | // we must resolve all the use decls | 3381 | // we must resolve all the use decls |
| 3469 | ImportTableEntry *import = get_scope_import(scope); | 3382 | ImportTableEntry *import = get_scope_import(scope); |
| ... | @@ -3625,7 +3538,7 @@ static bool is_container(TypeTableEntry *type_entry) { | ... | @@ -3625,7 +3538,7 @@ static bool is_container(TypeTableEntry *type_entry) { |
| 3625 | case TypeTableEntryIdNullLit: | 3538 | case TypeTableEntryIdNullLit: |
| 3626 | case TypeTableEntryIdMaybe: | 3539 | case TypeTableEntryIdMaybe: |
| 3627 | case TypeTableEntryIdErrorUnion: | 3540 | case TypeTableEntryIdErrorUnion: |
| 3628 | case TypeTableEntryIdPureError: | 3541 | case TypeTableEntryIdErrorSet: |
| 3629 | case TypeTableEntryIdFn: | 3542 | case TypeTableEntryIdFn: |
| 3630 | case TypeTableEntryIdNamespace: | 3543 | case TypeTableEntryIdNamespace: |
| 3631 | case TypeTableEntryIdBlock: | 3544 | case TypeTableEntryIdBlock: |
| ... | @@ -3673,7 +3586,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { | ... | @@ -3673,7 +3586,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { |
| 3673 | case TypeTableEntryIdNullLit: | 3586 | case TypeTableEntryIdNullLit: |
| 3674 | case TypeTableEntryIdMaybe: | 3587 | case TypeTableEntryIdMaybe: |
| 3675 | case TypeTableEntryIdErrorUnion: | 3588 | case TypeTableEntryIdErrorUnion: |
| 3676 | case TypeTableEntryIdPureError: | 3589 | case TypeTableEntryIdErrorSet: |
| 3677 | case TypeTableEntryIdFn: | 3590 | case TypeTableEntryIdFn: |
| 3678 | case TypeTableEntryIdNamespace: | 3591 | case TypeTableEntryIdNamespace: |
| 3679 | case TypeTableEntryIdBlock: | 3592 | case TypeTableEntryIdBlock: |
| ... | @@ -3765,6 +3678,27 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari | ... | @@ -3765,6 +3678,27 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari |
| 3765 | } | 3678 | } |
| 3766 | } | 3679 | } |
| 3767 | 3680 | ||
| 3681 | static 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 | |||
| 3768 | void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_type_node) { | 3702 | void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_type_node) { |
| 3769 | TypeTableEntry *fn_type = fn_table_entry->type_entry; | 3703 | TypeTableEntry *fn_type = fn_table_entry->type_entry; |
| 3770 | assert(!fn_type->data.fn.is_generic); | 3704 | assert(!fn_type->data.fn.is_generic); |
| ... | @@ -3774,14 +3708,49 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ | ... | @@ -3774,14 +3708,49 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ |
| 3774 | &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node); | 3708 | &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node); |
| 3775 | fn_table_entry->implicit_return_type = block_return_type; | 3709 | fn_table_entry->implicit_return_type = block_return_type; |
| 3776 | 3710 | ||
| 3777 | if (block_return_type->id == TypeTableEntryIdInvalid || | 3711 | if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) { |
| 3778 | fn_table_entry->analyzed_executable.invalid) | ||
| 3779 | { | ||
| 3780 | assert(g->errors.length > 0); | 3712 | assert(g->errors.length > 0); |
| 3781 | fn_table_entry->anal_state = FnAnalStateInvalid; | 3713 | fn_table_entry->anal_state = FnAnalStateInvalid; |
| 3782 | return; | 3714 | return; |
| 3783 | } | 3715 | } |
| 3784 | 3716 | ||
| 3717 | if (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) { | ||
| 3718 | TypeTableEntry *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type; | ||
| 3719 | if (return_err_set_type->data.error_set.infer_fn != nullptr) { | ||
| 3720 | TypeTableEntry *inferred_err_set_type; | ||
| 3721 | if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorSet) { | ||
| 3722 | inferred_err_set_type = fn_table_entry->implicit_return_type; | ||
| 3723 | } else if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorUnion) { | ||
| 3724 | inferred_err_set_type = fn_table_entry->implicit_return_type->data.error_union.err_set_type; | ||
| 3725 | } else { | ||
| 3726 | add_node_error(g, return_type_node, | ||
| 3727 | buf_sprintf("function with inferred error set must return at least one possible error")); | ||
| 3728 | fn_table_entry->anal_state = FnAnalStateInvalid; | ||
| 3729 | return; | ||
| 3730 | } | ||
| 3731 | |||
| 3732 | if (inferred_err_set_type->data.error_set.infer_fn != nullptr) { | ||
| 3733 | if (!analyze_resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) { | ||
| 3734 | fn_table_entry->anal_state = FnAnalStateInvalid; | ||
| 3735 | return; | ||
| 3736 | } | ||
| 3737 | } | ||
| 3738 | |||
| 3739 | return_err_set_type->data.error_set.infer_fn = nullptr; | ||
| 3740 | if (type_is_global_error_set(inferred_err_set_type)) { | ||
| 3741 | return_err_set_type->data.error_set.err_count = UINT32_MAX; | ||
| 3742 | } else { | ||
| 3743 | return_err_set_type->data.error_set.err_count = inferred_err_set_type->data.error_set.err_count; | ||
| 3744 | if (inferred_err_set_type->data.error_set.err_count > 0) { | ||
| 3745 | return_err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(inferred_err_set_type->data.error_set.err_count); | ||
| 3746 | for (uint32_t i = 0; i < inferred_err_set_type->data.error_set.err_count; i += 1) { | ||
| 3747 | return_err_set_type->data.error_set.errors[i] = inferred_err_set_type->data.error_set.errors[i]; | ||
| 3748 | } | ||
| 3749 | } | ||
| 3750 | } | ||
| 3751 | } | ||
| 3752 | } | ||
| 3753 | |||
| 3785 | if (g->verbose_ir) { | 3754 | if (g->verbose_ir) { |
| 3786 | fprintf(stderr, "{ // (analyzed)\n"); | 3755 | fprintf(stderr, "{ // (analyzed)\n"); |
| 3787 | ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4); | 3756 | ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4); |
| ... | @@ -3791,7 +3760,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ | ... | @@ -3791,7 +3760,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ |
| 3791 | fn_table_entry->anal_state = FnAnalStateComplete; | 3760 | fn_table_entry->anal_state = FnAnalStateComplete; |
| 3792 | } | 3761 | } |
| 3793 | 3762 | ||
| 3794 | static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { | 3763 | void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 3795 | assert(fn_table_entry->anal_state != FnAnalStateProbing); | 3764 | assert(fn_table_entry->anal_state != FnAnalStateProbing); |
| 3796 | if (fn_table_entry->anal_state != FnAnalStateReady) | 3765 | if (fn_table_entry->anal_state != FnAnalStateReady) |
| 3797 | return; | 3766 | return; |
| ... | @@ -4022,7 +3991,8 @@ void semantic_analyze(CodeGen *g) { | ... | @@ -4022,7 +3991,8 @@ void semantic_analyze(CodeGen *g) { |
| 4022 | for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) { | 3991 | for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) { |
| 4023 | Tld *tld = g->resolve_queue.at(g->resolve_queue_index); | 3992 | Tld *tld = g->resolve_queue.at(g->resolve_queue_index); |
| 4024 | bool pointer_only = false; | 3993 | bool pointer_only = false; |
| 4025 | resolve_top_level_decl(g, tld, pointer_only, nullptr); | 3994 | AstNode *source_node = nullptr; |
| 3995 | resolve_top_level_decl(g, tld, pointer_only, source_node); | ||
| 4026 | } | 3996 | } |
| 4027 | 3997 | ||
| 4028 | for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { | 3998 | for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { |
| ... | @@ -4114,7 +4084,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { | ... | @@ -4114,7 +4084,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { |
| 4114 | case TypeTableEntryIdInt: | 4084 | case TypeTableEntryIdInt: |
| 4115 | case TypeTableEntryIdFloat: | 4085 | case TypeTableEntryIdFloat: |
| 4116 | case TypeTableEntryIdPointer: | 4086 | case TypeTableEntryIdPointer: |
| 4117 | case TypeTableEntryIdPureError: | 4087 | case TypeTableEntryIdErrorSet: |
| 4118 | case TypeTableEntryIdFn: | 4088 | case TypeTableEntryIdFn: |
| 4119 | case TypeTableEntryIdEnum: | 4089 | case TypeTableEntryIdEnum: |
| 4120 | return false; | 4090 | return false; |
| ... | @@ -4122,7 +4092,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { | ... | @@ -4122,7 +4092,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { |
| 4122 | case TypeTableEntryIdStruct: | 4092 | case TypeTableEntryIdStruct: |
| 4123 | return type_has_bits(type_entry); | 4093 | return type_has_bits(type_entry); |
| 4124 | case TypeTableEntryIdErrorUnion: | 4094 | case TypeTableEntryIdErrorUnion: |
| 4125 | return type_has_bits(type_entry->data.error.child_type); | 4095 | return type_has_bits(type_entry->data.error_union.payload_type); |
| 4126 | case TypeTableEntryIdMaybe: | 4096 | case TypeTableEntryIdMaybe: |
| 4127 | return type_has_bits(type_entry->data.maybe.child_type) && | 4097 | return type_has_bits(type_entry->data.maybe.child_type) && |
| 4128 | type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer && | 4098 | type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer && |
| ... | @@ -4386,9 +4356,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { | ... | @@ -4386,9 +4356,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { |
| 4386 | case TypeTableEntryIdErrorUnion: | 4356 | case TypeTableEntryIdErrorUnion: |
| 4387 | // TODO better hashing algorithm | 4357 | // TODO better hashing algorithm |
| 4388 | return 3415065496; | 4358 | return 3415065496; |
| 4389 | case TypeTableEntryIdPureError: | 4359 | case TypeTableEntryIdErrorSet: |
| 4390 | // TODO better hashing algorithm | 4360 | assert(const_val->data.x_err_set != nullptr); |
| 4391 | return 2630160122; | 4361 | return const_val->data.x_err_set->value ^ 2630160122; |
| 4392 | case TypeTableEntryIdFn: | 4362 | case TypeTableEntryIdFn: |
| 4393 | return 4133894920 ^ hash_ptr(const_val->data.x_fn.fn_entry); | 4363 | return 4133894920 ^ hash_ptr(const_val->data.x_fn.fn_entry); |
| 4394 | case TypeTableEntryIdNamespace: | 4364 | case TypeTableEntryIdNamespace: |
| ... | @@ -4515,7 +4485,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) { | ... | @@ -4515,7 +4485,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) { |
| 4515 | case TypeTableEntryIdMaybe: | 4485 | case TypeTableEntryIdMaybe: |
| 4516 | case TypeTableEntryIdErrorUnion: | 4486 | case TypeTableEntryIdErrorUnion: |
| 4517 | case TypeTableEntryIdEnum: | 4487 | case TypeTableEntryIdEnum: |
| 4518 | case TypeTableEntryIdPureError: | 4488 | case TypeTableEntryIdErrorSet: |
| 4519 | case TypeTableEntryIdFn: | 4489 | case TypeTableEntryIdFn: |
| 4520 | case TypeTableEntryIdBool: | 4490 | case TypeTableEntryIdBool: |
| 4521 | case TypeTableEntryIdInt: | 4491 | case TypeTableEntryIdInt: |
| ... | @@ -4894,8 +4864,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { | ... | @@ -4894,8 +4864,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { |
| 4894 | return a->data.x_type == b->data.x_type; | 4864 | return a->data.x_type == b->data.x_type; |
| 4895 | case TypeTableEntryIdVoid: | 4865 | case TypeTableEntryIdVoid: |
| 4896 | return true; | 4866 | return true; |
| 4897 | case TypeTableEntryIdPureError: | 4867 | case TypeTableEntryIdErrorSet: |
| 4898 | return a->data.x_pure_err == b->data.x_pure_err; | 4868 | return a->data.x_err_set->value == b->data.x_err_set->value; |
| 4899 | case TypeTableEntryIdFn: | 4869 | case TypeTableEntryIdFn: |
| 4900 | return a->data.x_fn.fn_entry == b->data.x_fn.fn_entry; | 4870 | return a->data.x_fn.fn_entry == b->data.x_fn.fn_entry; |
| 4901 | case TypeTableEntryIdBool: | 4871 | case TypeTableEntryIdBool: |
| ... | @@ -5256,9 +5226,9 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { | ... | @@ -5256,9 +5226,9 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 5256 | buf_appendf(buf, "(union %s constant)", buf_ptr(&type_entry->name)); | 5226 | buf_appendf(buf, "(union %s constant)", buf_ptr(&type_entry->name)); |
| 5257 | return; | 5227 | return; |
| 5258 | } | 5228 | } |
| 5259 | case TypeTableEntryIdPureError: | 5229 | case TypeTableEntryIdErrorSet: |
| 5260 | { | 5230 | { |
| 5261 | buf_appendf(buf, "(pure error constant)"); | 5231 | buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name)); |
| 5262 | return; | 5232 | return; |
| 5263 | } | 5233 | } |
| 5264 | case TypeTableEntryIdArgTuple: | 5234 | case TypeTableEntryIdArgTuple: |
| ... | @@ -5319,8 +5289,7 @@ uint32_t type_id_hash(TypeId x) { | ... | @@ -5319,8 +5289,7 @@ uint32_t type_id_hash(TypeId x) { |
| 5319 | case TypeTableEntryIdUndefLit: | 5289 | case TypeTableEntryIdUndefLit: |
| 5320 | case TypeTableEntryIdNullLit: | 5290 | case TypeTableEntryIdNullLit: |
| 5321 | case TypeTableEntryIdMaybe: | 5291 | case TypeTableEntryIdMaybe: |
| 5322 | case TypeTableEntryIdErrorUnion: | 5292 | case TypeTableEntryIdErrorSet: |
| 5323 | case TypeTableEntryIdPureError: | ||
| 5324 | case TypeTableEntryIdEnum: | 5293 | case TypeTableEntryIdEnum: |
| 5325 | case TypeTableEntryIdUnion: | 5294 | case TypeTableEntryIdUnion: |
| 5326 | case TypeTableEntryIdFn: | 5295 | case TypeTableEntryIdFn: |
| ... | @@ -5329,6 +5298,8 @@ uint32_t type_id_hash(TypeId x) { | ... | @@ -5329,6 +5298,8 @@ uint32_t type_id_hash(TypeId x) { |
| 5329 | case TypeTableEntryIdBoundFn: | 5298 | case TypeTableEntryIdBoundFn: |
| 5330 | case TypeTableEntryIdArgTuple: | 5299 | case TypeTableEntryIdArgTuple: |
| 5331 | zig_unreachable(); | 5300 | zig_unreachable(); |
| 5301 | case TypeTableEntryIdErrorUnion: | ||
| 5302 | return hash_ptr(x.data.error_union.err_set_type) ^ hash_ptr(x.data.error_union.payload_type); | ||
| 5332 | case TypeTableEntryIdPointer: | 5303 | case TypeTableEntryIdPointer: |
| 5333 | return hash_ptr(x.data.pointer.child_type) + | 5304 | return hash_ptr(x.data.pointer.child_type) + |
| 5334 | (x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) + | 5305 | (x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) + |
| ... | @@ -5363,8 +5334,7 @@ bool type_id_eql(TypeId a, TypeId b) { | ... | @@ -5363,8 +5334,7 @@ bool type_id_eql(TypeId a, TypeId b) { |
| 5363 | case TypeTableEntryIdUndefLit: | 5334 | case TypeTableEntryIdUndefLit: |
| 5364 | case TypeTableEntryIdNullLit: | 5335 | case TypeTableEntryIdNullLit: |
| 5365 | case TypeTableEntryIdMaybe: | 5336 | case TypeTableEntryIdMaybe: |
| 5366 | case TypeTableEntryIdErrorUnion: | 5337 | case TypeTableEntryIdErrorSet: |
| 5367 | case TypeTableEntryIdPureError: | ||
| 5368 | case TypeTableEntryIdEnum: | 5338 | case TypeTableEntryIdEnum: |
| 5369 | case TypeTableEntryIdUnion: | 5339 | case TypeTableEntryIdUnion: |
| 5370 | case TypeTableEntryIdFn: | 5340 | case TypeTableEntryIdFn: |
| ... | @@ -5374,6 +5344,10 @@ bool type_id_eql(TypeId a, TypeId b) { | ... | @@ -5374,6 +5344,10 @@ bool type_id_eql(TypeId a, TypeId b) { |
| 5374 | case TypeTableEntryIdArgTuple: | 5344 | case TypeTableEntryIdArgTuple: |
| 5375 | case TypeTableEntryIdOpaque: | 5345 | case TypeTableEntryIdOpaque: |
| 5376 | zig_unreachable(); | 5346 | zig_unreachable(); |
| 5347 | case TypeTableEntryIdErrorUnion: | ||
| 5348 | return a.data.error_union.err_set_type == b.data.error_union.err_set_type && | ||
| 5349 | a.data.error_union.payload_type == b.data.error_union.payload_type; | ||
| 5350 | |||
| 5377 | case TypeTableEntryIdPointer: | 5351 | case TypeTableEntryIdPointer: |
| 5378 | return a.data.pointer.child_type == b.data.pointer.child_type && | 5352 | return a.data.pointer.child_type == b.data.pointer.child_type && |
| 5379 | a.data.pointer.is_const == b.data.pointer.is_const && | 5353 | a.data.pointer.is_const == b.data.pointer.is_const && |
| ... | @@ -5478,7 +5452,7 @@ static const TypeTableEntryId all_type_ids[] = { | ... | @@ -5478,7 +5452,7 @@ static const TypeTableEntryId all_type_ids[] = { |
| 5478 | TypeTableEntryIdNullLit, | 5452 | TypeTableEntryIdNullLit, |
| 5479 | TypeTableEntryIdMaybe, | 5453 | TypeTableEntryIdMaybe, |
| 5480 | TypeTableEntryIdErrorUnion, | 5454 | TypeTableEntryIdErrorUnion, |
| 5481 | TypeTableEntryIdPureError, | 5455 | TypeTableEntryIdErrorSet, |
| 5482 | TypeTableEntryIdEnum, | 5456 | TypeTableEntryIdEnum, |
| 5483 | TypeTableEntryIdUnion, | 5457 | TypeTableEntryIdUnion, |
| 5484 | TypeTableEntryIdFn, | 5458 | TypeTableEntryIdFn, |
| ... | @@ -5533,7 +5507,7 @@ size_t type_id_index(TypeTableEntryId id) { | ... | @@ -5533,7 +5507,7 @@ size_t type_id_index(TypeTableEntryId id) { |
| 5533 | return 13; | 5507 | return 13; |
| 5534 | case TypeTableEntryIdErrorUnion: | 5508 | case TypeTableEntryIdErrorUnion: |
| 5535 | return 14; | 5509 | return 14; |
| 5536 | case TypeTableEntryIdPureError: | 5510 | case TypeTableEntryIdErrorSet: |
| 5537 | return 15; | 5511 | return 15; |
| 5538 | case TypeTableEntryIdEnum: | 5512 | case TypeTableEntryIdEnum: |
| 5539 | return 16; | 5513 | return 16; |
| ... | @@ -5590,8 +5564,8 @@ const char *type_id_name(TypeTableEntryId id) { | ... | @@ -5590,8 +5564,8 @@ const char *type_id_name(TypeTableEntryId id) { |
| 5590 | return "Nullable"; | 5564 | return "Nullable"; |
| 5591 | case TypeTableEntryIdErrorUnion: | 5565 | case TypeTableEntryIdErrorUnion: |
| 5592 | return "ErrorUnion"; | 5566 | return "ErrorUnion"; |
| 5593 | case TypeTableEntryIdPureError: | 5567 | case TypeTableEntryIdErrorSet: |
| 5594 | return "Error"; | 5568 | return "ErrorSet"; |
| 5595 | case TypeTableEntryIdEnum: | 5569 | case TypeTableEntryIdEnum: |
| 5596 | return "Enum"; | 5570 | return "Enum"; |
| 5597 | case TypeTableEntryIdUnion: | 5571 | case TypeTableEntryIdUnion: |
| ... | @@ -5640,17 +5614,6 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) { | ... | @@ -5640,17 +5614,6 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) { |
| 5640 | return link_lib; | 5614 | return link_lib; |
| 5641 | } | 5615 | } |
| 5642 | 5616 | ||
| 5643 | void 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 | |||
| 5654 | uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) { | 5617 | uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) { |
| 5655 | type_ensure_zero_bits_known(g, type_entry); | 5618 | type_ensure_zero_bits_known(g, type_entry); |
| 5656 | if (type_entry->zero_bits) return 0; | 5619 | if (type_entry->zero_bits) return 0; |
| ... | @@ -5696,3 +5659,8 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { | ... | @@ -5696,3 +5659,8 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { |
| 5696 | return var_value; | 5659 | return var_value; |
| 5697 | } | 5660 | } |
| 5698 | 5661 | ||
| 5662 | bool type_is_global_error_set(TypeTableEntry *err_set_type) { | ||
| 5663 | assert(err_set_type->id == TypeTableEntryIdErrorSet); | ||
| 5664 | assert(err_set_type->data.error_set.infer_fn == nullptr); | ||
| 5665 | return err_set_type->data.error_set.err_count == UINT32_MAX; | ||
| 5666 | } |
src/analyze.hpp+4-4| ... | @@ -30,7 +30,7 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type); | ... | @@ -30,7 +30,7 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type); |
| 30 | TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind, | 30 | TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind, |
| 31 | AstNode *decl_node, const char *name, ContainerLayout layout); | 31 | AstNode *decl_node, const char *name, ContainerLayout layout); |
| 32 | TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x); | 32 | TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x); |
| 33 | TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type); | 33 | TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, TypeTableEntry *payload_type); |
| 34 | TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry); | 34 | TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry); |
| 35 | TypeTableEntry *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *name); | 35 | TypeTableEntry *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *name); |
| 36 | TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[], | 36 | TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[], |
| ... | @@ -46,8 +46,6 @@ bool type_has_bits(TypeTableEntry *type_entry); | ... | @@ -46,8 +46,6 @@ bool type_has_bits(TypeTableEntry *type_entry); |
| 46 | ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code); | 46 | ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code); |
| 47 | 47 | ||
| 48 | 48 | ||
| 49 | // TODO move these over, these used to be static | ||
| 50 | bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type); | ||
| 51 | VariableTableEntry *find_variable(CodeGen *g, Scope *orig_context, Buf *name); | 49 | VariableTableEntry *find_variable(CodeGen *g, Scope *orig_context, Buf *name); |
| 52 | Tld *find_decl(CodeGen *g, Scope *scope, Buf *name); | 50 | Tld *find_decl(CodeGen *g, Scope *scope, Buf *name); |
| 53 | void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node); | 51 | void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node); |
| ... | @@ -58,6 +56,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt | ... | @@ -58,6 +56,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt |
| 58 | TypeTableEntry *container_ref_type(TypeTableEntry *type_entry); | 56 | TypeTableEntry *container_ref_type(TypeTableEntry *type_entry); |
| 59 | bool type_is_complete(TypeTableEntry *type_entry); | 57 | bool type_is_complete(TypeTableEntry *type_entry); |
| 60 | bool type_is_invalid(TypeTableEntry *type_entry); | 58 | bool type_is_invalid(TypeTableEntry *type_entry); |
| 59 | bool type_is_global_error_set(TypeTableEntry *err_set_type); | ||
| 61 | bool type_has_zero_bits_known(TypeTableEntry *type_entry); | 60 | bool type_has_zero_bits_known(TypeTableEntry *type_entry); |
| 62 | void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry); | 61 | void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry); |
| 63 | ScopeDecls *get_container_scope(TypeTableEntry *type_entry); | 62 | ScopeDecls *get_container_scope(TypeTableEntry *type_entry); |
| ... | @@ -176,7 +175,6 @@ bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry); | ... | @@ -176,7 +175,6 @@ bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry); |
| 176 | LinkLib *create_link_lib(Buf *name); | 175 | LinkLib *create_link_lib(Buf *name); |
| 177 | bool calling_convention_does_first_arg_return(CallingConvention cc); | 176 | bool calling_convention_does_first_arg_return(CallingConvention cc); |
| 178 | LinkLib *add_link_lib(CodeGen *codegen, Buf *lib); | 177 | LinkLib *add_link_lib(CodeGen *codegen, Buf *lib); |
| 179 | void add_link_lib_symbol(CodeGen *g, Buf *lib_name, Buf *symbol_name); | ||
| 180 | 178 | ||
| 181 | uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry); | 179 | uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry); |
| 182 | TypeTableEntry *get_align_amt_type(CodeGen *g); | 180 | TypeTableEntry *get_align_amt_type(CodeGen *g); |
| ... | @@ -188,6 +186,8 @@ void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, G | ... | @@ -188,6 +186,8 @@ void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, G |
| 188 | 186 | ||
| 189 | ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name); | 187 | ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name); |
| 190 | TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g); | 188 | TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g); |
| 189 | void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry); | ||
| 191 | 190 | ||
| 191 | TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry); | ||
| 192 | 192 | ||
| 193 | #endif | 193 | #endif |
src/ast_render.cpp+26-7| ... | @@ -49,11 +49,12 @@ static const char *bin_op_str(BinOpType bin_op) { | ... | @@ -49,11 +49,12 @@ static const char *bin_op_str(BinOpType bin_op) { |
| 49 | case BinOpTypeAssignBitAnd: return "&="; | 49 | case BinOpTypeAssignBitAnd: return "&="; |
| 50 | case BinOpTypeAssignBitXor: return "^="; | 50 | case BinOpTypeAssignBitXor: return "^="; |
| 51 | case BinOpTypeAssignBitOr: return "|="; | 51 | case BinOpTypeAssignBitOr: return "|="; |
| 52 | case BinOpTypeAssignBoolAnd: return "&&="; | 52 | case BinOpTypeAssignMergeErrorSets: return "||="; |
| 53 | case BinOpTypeAssignBoolOr: return "||="; | ||
| 54 | case BinOpTypeUnwrapMaybe: return "??"; | 53 | case BinOpTypeUnwrapMaybe: return "??"; |
| 55 | case BinOpTypeArrayCat: return "++"; | 54 | case BinOpTypeArrayCat: return "++"; |
| 56 | case BinOpTypeArrayMult: return "**"; | 55 | case BinOpTypeArrayMult: return "**"; |
| 56 | case BinOpTypeErrorUnion: return "!"; | ||
| 57 | case BinOpTypeMergeErrorSets: return "||"; | ||
| 57 | } | 58 | } |
| 58 | zig_unreachable(); | 59 | zig_unreachable(); |
| 59 | } | 60 | } |
| ... | @@ -67,7 +68,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) { | ... | @@ -67,7 +68,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) { |
| 67 | case PrefixOpBinNot: return "~"; | 68 | case PrefixOpBinNot: return "~"; |
| 68 | case PrefixOpDereference: return "*"; | 69 | case PrefixOpDereference: return "*"; |
| 69 | case PrefixOpMaybe: return "?"; | 70 | case PrefixOpMaybe: return "?"; |
| 70 | case PrefixOpError: return "%"; | ||
| 71 | case PrefixOpUnwrapMaybe: return "??"; | 71 | case PrefixOpUnwrapMaybe: return "??"; |
| 72 | } | 72 | } |
| 73 | zig_unreachable(); | 73 | zig_unreachable(); |
| ... | @@ -174,8 +174,6 @@ static const char *node_type_str(NodeType node_type) { | ... | @@ -174,8 +174,6 @@ static const char *node_type_str(NodeType node_type) { |
| 174 | return "Defer"; | 174 | return "Defer"; |
| 175 | case NodeTypeVariableDeclaration: | 175 | case NodeTypeVariableDeclaration: |
| 176 | return "VariableDeclaration"; | 176 | return "VariableDeclaration"; |
| 177 | case NodeTypeErrorValueDecl: | ||
| 178 | return "ErrorValueDecl"; | ||
| 179 | case NodeTypeTestDecl: | 177 | case NodeTypeTestDecl: |
| 180 | return "TestDecl"; | 178 | return "TestDecl"; |
| 181 | case NodeTypeIntLiteral: | 179 | case NodeTypeIntLiteral: |
| ... | @@ -244,6 +242,8 @@ static const char *node_type_str(NodeType node_type) { | ... | @@ -244,6 +242,8 @@ static const char *node_type_str(NodeType node_type) { |
| 244 | return "IfErrorExpr"; | 242 | return "IfErrorExpr"; |
| 245 | case NodeTypeTestExpr: | 243 | case NodeTypeTestExpr: |
| 246 | return "TestExpr"; | 244 | return "TestExpr"; |
| 245 | case NodeTypeErrorSetDecl: | ||
| 246 | return "ErrorSetDecl"; | ||
| 247 | } | 247 | } |
| 248 | zig_unreachable(); | 248 | zig_unreachable(); |
| 249 | } | 249 | } |
| ... | @@ -396,7 +396,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -396,7 +396,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 396 | 396 | ||
| 397 | if (child->type == NodeTypeUse || | 397 | if (child->type == NodeTypeUse || |
| 398 | child->type == NodeTypeVariableDeclaration || | 398 | child->type == NodeTypeVariableDeclaration || |
| 399 | child->type == NodeTypeErrorValueDecl || | ||
| 400 | child->type == NodeTypeFnProto) | 399 | child->type == NodeTypeFnProto) |
| 401 | { | 400 | { |
| 402 | fprintf(ar->f, ";"); | 401 | fprintf(ar->f, ";"); |
| ... | @@ -452,6 +451,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -452,6 +451,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 452 | AstNode *return_type_node = node->data.fn_proto.return_type; | 451 | AstNode *return_type_node = node->data.fn_proto.return_type; |
| 453 | assert(return_type_node != nullptr); | 452 | assert(return_type_node != nullptr); |
| 454 | fprintf(ar->f, " "); | 453 | fprintf(ar->f, " "); |
| 454 | if (node->data.fn_proto.auto_err_set) { | ||
| 455 | fprintf(ar->f, "!"); | ||
| 456 | } | ||
| 455 | render_node_grouped(ar, return_type_node); | 457 | render_node_grouped(ar, return_type_node); |
| 456 | break; | 458 | break; |
| 457 | } | 459 | } |
| ... | @@ -1017,9 +1019,26 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -1017,9 +1019,26 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 1017 | render_node_ungrouped(ar, node->data.unwrap_err_expr.op2); | 1019 | render_node_ungrouped(ar, node->data.unwrap_err_expr.op2); |
| 1018 | break; | 1020 | break; |
| 1019 | } | 1021 | } |
| 1022 | case NodeTypeErrorSetDecl: | ||
| 1023 | { | ||
| 1024 | fprintf(ar->f, "error {\n"); | ||
| 1025 | ar->indent += ar->indent_size; | ||
| 1026 | |||
| 1027 | for (size_t i = 0; i < node->data.err_set_decl.decls.length; i += 1) { | ||
| 1028 | AstNode *field_node = node->data.err_set_decl.decls.at(i); | ||
| 1029 | assert(field_node->type == NodeTypeSymbol); | ||
| 1030 | print_indent(ar); | ||
| 1031 | print_symbol(ar, field_node->data.symbol_expr.symbol); | ||
| 1032 | fprintf(ar->f, ",\n"); | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | ar->indent -= ar->indent_size; | ||
| 1036 | print_indent(ar); | ||
| 1037 | fprintf(ar->f, "}"); | ||
| 1038 | break; | ||
| 1039 | } | ||
| 1020 | case NodeTypeFnDecl: | 1040 | case NodeTypeFnDecl: |
| 1021 | case NodeTypeParamDecl: | 1041 | case NodeTypeParamDecl: |
| 1022 | case NodeTypeErrorValueDecl: | ||
| 1023 | case NodeTypeTestDecl: | 1042 | case NodeTypeTestDecl: |
| 1024 | case NodeTypeStructField: | 1043 | case NodeTypeStructField: |
| 1025 | case NodeTypeUse: | 1044 | case NodeTypeUse: |
src/codegen.cpp+156-76| ... | @@ -92,9 +92,6 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out | ... | @@ -92,9 +92,6 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out |
| 92 | g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib); | 92 | g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib); |
| 93 | buf_resize(&g->global_asm, 0); | 93 | buf_resize(&g->global_asm, 0); |
| 94 | 94 | ||
| 95 | // reserve index 0 to indicate no error | ||
| 96 | g->error_decls.append(nullptr); | ||
| 97 | |||
| 98 | if (root_src_path) { | 95 | if (root_src_path) { |
| 99 | Buf *src_basename = buf_alloc(); | 96 | Buf *src_basename = buf_alloc(); |
| 100 | Buf *src_dir = buf_alloc(); | 97 | Buf *src_dir = buf_alloc(); |
| ... | @@ -256,6 +253,10 @@ LinkLib *codegen_add_link_lib(CodeGen *g, Buf *name) { | ... | @@ -256,6 +253,10 @@ LinkLib *codegen_add_link_lib(CodeGen *g, Buf *name) { |
| 256 | return add_link_lib(g, name); | 253 | return add_link_lib(g, name); |
| 257 | } | 254 | } |
| 258 | 255 | ||
| 256 | void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib) { | ||
| 257 | codegen->forbidden_libs.append(lib); | ||
| 258 | } | ||
| 259 | |||
| 259 | void codegen_add_framework(CodeGen *g, const char *framework) { | 260 | void codegen_add_framework(CodeGen *g, const char *framework) { |
| 260 | g->darwin_frameworks.append(buf_create_from_str(framework)); | 261 | g->darwin_frameworks.append(buf_create_from_str(framework)); |
| 261 | } | 262 | } |
| ... | @@ -410,7 +411,7 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e | ... | @@ -410,7 +411,7 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e |
| 410 | } | 411 | } |
| 411 | TypeTableEntry *fn_type = fn_table_entry->type_entry; | 412 | TypeTableEntry *fn_type = fn_table_entry->type_entry; |
| 412 | TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type; | 413 | TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type; |
| 413 | if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdPureError) { | 414 | if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdErrorSet) { |
| 414 | return UINT32_MAX; | 415 | return UINT32_MAX; |
| 415 | } | 416 | } |
| 416 | bool first_arg_ret = type_has_bits(return_type) && handle_is_ptr(return_type); | 417 | bool first_arg_ret = type_has_bits(return_type) && handle_is_ptr(return_type); |
| ... | @@ -1442,7 +1443,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns | ... | @@ -1442,7 +1443,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns |
| 1442 | is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError; | 1443 | is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError; |
| 1443 | // TODO: emit a branch to check if the return value is an error | 1444 | // TODO: emit a branch to check if the return value is an error |
| 1444 | } | 1445 | } |
| 1445 | } else if (return_type->id == TypeTableEntryIdPureError) { | 1446 | } else if (return_type->id == TypeTableEntryIdErrorSet) { |
| 1446 | is_err_return = true; | 1447 | is_err_return = true; |
| 1447 | } | 1448 | } |
| 1448 | if (is_err_return) { | 1449 | if (is_err_return) { |
| ... | @@ -1789,7 +1790,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -1789,7 +1790,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 1789 | 1790 | ||
| 1790 | assert(op1->value.type == op2->value.type || op_id == IrBinOpBitShiftLeftLossy || | 1791 | assert(op1->value.type == op2->value.type || op_id == IrBinOpBitShiftLeftLossy || |
| 1791 | op_id == IrBinOpBitShiftLeftExact || op_id == IrBinOpBitShiftRightLossy || | 1792 | op_id == IrBinOpBitShiftLeftExact || op_id == IrBinOpBitShiftRightLossy || |
| 1792 | op_id == IrBinOpBitShiftRightExact); | 1793 | op_id == IrBinOpBitShiftRightExact || |
| 1794 | (op1->value.type->id == TypeTableEntryIdErrorSet && op2->value.type->id == TypeTableEntryIdErrorSet)); | ||
| 1793 | TypeTableEntry *type_entry = op1->value.type; | 1795 | TypeTableEntry *type_entry = op1->value.type; |
| 1794 | 1796 | ||
| 1795 | bool want_runtime_safety = bin_op_instruction->safety_check_on && | 1797 | bool want_runtime_safety = bin_op_instruction->safety_check_on && |
| ... | @@ -1802,6 +1804,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -1802,6 +1804,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 1802 | case IrBinOpArrayCat: | 1804 | case IrBinOpArrayCat: |
| 1803 | case IrBinOpArrayMult: | 1805 | case IrBinOpArrayMult: |
| 1804 | case IrBinOpRemUnspecified: | 1806 | case IrBinOpRemUnspecified: |
| 1807 | case IrBinOpMergeErrorSets: | ||
| 1805 | zig_unreachable(); | 1808 | zig_unreachable(); |
| 1806 | case IrBinOpBoolOr: | 1809 | case IrBinOpBoolOr: |
| 1807 | return LLVMBuildOr(g->builder, op1_value, op2_value, ""); | 1810 | return LLVMBuildOr(g->builder, op1_value, op2_value, ""); |
| ... | @@ -1823,7 +1826,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -1823,7 +1826,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 1823 | } else if (type_entry->id == TypeTableEntryIdEnum) { | 1826 | } else if (type_entry->id == TypeTableEntryIdEnum) { |
| 1824 | LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); | 1827 | LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); |
| 1825 | return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); | 1828 | return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); |
| 1826 | } else if (type_entry->id == TypeTableEntryIdPureError || | 1829 | } else if (type_entry->id == TypeTableEntryIdErrorSet || |
| 1827 | type_entry->id == TypeTableEntryIdPointer || | 1830 | type_entry->id == TypeTableEntryIdPointer || |
| 1828 | type_entry->id == TypeTableEntryIdBool) | 1831 | type_entry->id == TypeTableEntryIdBool) |
| 1829 | { | 1832 | { |
| ... | @@ -1955,6 +1958,54 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -1955,6 +1958,54 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 1955 | zig_unreachable(); | 1958 | zig_unreachable(); |
| 1956 | } | 1959 | } |
| 1957 | 1960 | ||
| 1961 | static 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 | |||
| 1958 | static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, | 2009 | static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, |
| 1959 | IrInstructionCast *cast_instruction) | 2010 | IrInstructionCast *cast_instruction) |
| 1960 | { | 2011 | { |
| ... | @@ -2078,6 +2129,11 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, | ... | @@ -2078,6 +2129,11 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, |
| 2078 | assert(wanted_type->id == TypeTableEntryIdInt); | 2129 | assert(wanted_type->id == TypeTableEntryIdInt); |
| 2079 | assert(actual_type->id == TypeTableEntryIdBool); | 2130 | assert(actual_type->id == TypeTableEntryIdBool); |
| 2080 | return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, ""); | 2131 | return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, ""); |
| 2132 | case CastOpErrSet: | ||
| 2133 | if (ir_want_runtime_safety(g, &cast_instruction->base)) { | ||
| 2134 | add_error_range_check(g, wanted_type, g->err_tag_type, expr_val); | ||
| 2135 | } | ||
| 2136 | return expr_val; | ||
| 2081 | } | 2137 | } |
| 2082 | zig_unreachable(); | 2138 | zig_unreachable(); |
| 2083 | } | 2139 | } |
| ... | @@ -2139,7 +2195,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable, | ... | @@ -2139,7 +2195,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable, |
| 2139 | 2195 | ||
| 2140 | static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) { | 2196 | static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) { |
| 2141 | TypeTableEntry *wanted_type = instruction->base.value.type; | 2197 | TypeTableEntry *wanted_type = instruction->base.value.type; |
| 2142 | assert(wanted_type->id == TypeTableEntryIdPureError); | 2198 | assert(wanted_type->id == TypeTableEntryIdErrorSet); |
| 2143 | 2199 | ||
| 2144 | TypeTableEntry *actual_type = instruction->target->value.type; | 2200 | TypeTableEntry *actual_type = instruction->target->value.type; |
| 2145 | assert(actual_type->id == TypeTableEntryIdInt); | 2201 | assert(actual_type->id == TypeTableEntryIdInt); |
| ... | @@ -2148,32 +2204,7 @@ static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, I | ... | @@ -2148,32 +2204,7 @@ static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, I |
| 2148 | LLVMValueRef target_val = ir_llvm_value(g, instruction->target); | 2204 | LLVMValueRef target_val = ir_llvm_value(g, instruction->target); |
| 2149 | 2205 | ||
| 2150 | if (ir_want_runtime_safety(g, &instruction->base)) { | 2206 | if (ir_want_runtime_safety(g, &instruction->base)) { |
| 2151 | LLVMValueRef zero = LLVMConstNull(actual_type->type_ref); | 2207 | add_error_range_check(g, wanted_type, actual_type, target_val); |
| 2152 | LLVMValueRef neq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target_val, zero, ""); | ||
| 2153 | LLVMValueRef ok_bit; | ||
| 2154 | |||
| 2155 | BigInt biggest_possible_err_val = {0}; | ||
| 2156 | eval_min_max_value_int(g, actual_type, &biggest_possible_err_val, true); | ||
| 2157 | |||
| 2158 | if (bigint_fits_in_bits(&biggest_possible_err_val, 64, false) && | ||
| 2159 | bigint_as_unsigned(&biggest_possible_err_val) < g->error_decls.length) | ||
| 2160 | { | ||
| 2161 | ok_bit = neq_zero_bit; | ||
| 2162 | } else { | ||
| 2163 | LLVMValueRef error_value_count = LLVMConstInt(actual_type->type_ref, g->error_decls.length, false); | ||
| 2164 | LLVMValueRef in_bounds_bit = LLVMBuildICmp(g->builder, LLVMIntULT, target_val, error_value_count, ""); | ||
| 2165 | ok_bit = LLVMBuildAnd(g->builder, neq_zero_bit, in_bounds_bit, ""); | ||
| 2166 | } | ||
| 2167 | |||
| 2168 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrOk"); | ||
| 2169 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrFail"); | ||
| 2170 | |||
| 2171 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); | ||
| 2172 | |||
| 2173 | LLVMPositionBuilderAtEnd(g->builder, fail_block); | ||
| 2174 | gen_safety_crash(g, PanicMsgIdInvalidErrorCode); | ||
| 2175 | |||
| 2176 | LLVMPositionBuilderAtEnd(g->builder, ok_block); | ||
| 2177 | } | 2208 | } |
| 2178 | 2209 | ||
| 2179 | return gen_widen_or_shorten(g, false, actual_type, g->err_tag_type, target_val); | 2210 | return gen_widen_or_shorten(g, false, actual_type, g->err_tag_type, target_val); |
| ... | @@ -2187,15 +2218,18 @@ static LLVMValueRef ir_render_err_to_int(CodeGen *g, IrExecutable *executable, I | ... | @@ -2187,15 +2218,18 @@ static LLVMValueRef ir_render_err_to_int(CodeGen *g, IrExecutable *executable, I |
| 2187 | TypeTableEntry *actual_type = instruction->target->value.type; | 2218 | TypeTableEntry *actual_type = instruction->target->value.type; |
| 2188 | LLVMValueRef target_val = ir_llvm_value(g, instruction->target); | 2219 | LLVMValueRef target_val = ir_llvm_value(g, instruction->target); |
| 2189 | 2220 | ||
| 2190 | if (actual_type->id == TypeTableEntryIdPureError) { | 2221 | if (actual_type->id == TypeTableEntryIdErrorSet) { |
| 2191 | return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), | 2222 | return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), |
| 2192 | g->err_tag_type, wanted_type, target_val); | 2223 | g->err_tag_type, wanted_type, target_val); |
| 2193 | } else if (actual_type->id == TypeTableEntryIdErrorUnion) { | 2224 | } else if (actual_type->id == TypeTableEntryIdErrorUnion) { |
| 2194 | if (!type_has_bits(actual_type->data.error.child_type)) { | 2225 | // this should have been a compile time constant |
| 2226 | assert(type_has_bits(actual_type->data.error_union.err_set_type)); | ||
| 2227 | |||
| 2228 | if (!type_has_bits(actual_type->data.error_union.payload_type)) { | ||
| 2195 | return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), | 2229 | return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), |
| 2196 | g->err_tag_type, wanted_type, target_val); | 2230 | g->err_tag_type, wanted_type, target_val); |
| 2197 | } else { | 2231 | } else { |
| 2198 | zig_panic("TODO"); | 2232 | zig_panic("TODO err to int when error union payload type not void"); |
| 2199 | } | 2233 | } |
| 2200 | } else { | 2234 | } else { |
| 2201 | zig_unreachable(); | 2235 | zig_unreachable(); |
| ... | @@ -2235,7 +2269,6 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst | ... | @@ -2235,7 +2269,6 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst |
| 2235 | 2269 | ||
| 2236 | switch (op_id) { | 2270 | switch (op_id) { |
| 2237 | case IrUnOpInvalid: | 2271 | case IrUnOpInvalid: |
| 2238 | case IrUnOpError: | ||
| 2239 | case IrUnOpMaybe: | 2272 | case IrUnOpMaybe: |
| 2240 | case IrUnOpDereference: | 2273 | case IrUnOpDereference: |
| 2241 | zig_unreachable(); | 2274 | zig_unreachable(); |
| ... | @@ -2489,7 +2522,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -2489,7 +2522,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 2489 | TypeTableEntry *src_return_type = fn_type_id->return_type; | 2522 | TypeTableEntry *src_return_type = fn_type_id->return_type; |
| 2490 | bool ret_has_bits = type_has_bits(src_return_type); | 2523 | bool ret_has_bits = type_has_bits(src_return_type); |
| 2491 | bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type); | 2524 | bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type); |
| 2492 | bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdPureError); | 2525 | bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdErrorSet); |
| 2493 | size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0); | 2526 | size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0); |
| 2494 | bool is_var_args = fn_type_id->is_var_args; | 2527 | bool is_var_args = fn_type_id->is_var_args; |
| 2495 | LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count); | 2528 | LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count); |
| ... | @@ -2907,7 +2940,7 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstru | ... | @@ -2907,7 +2940,7 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstru |
| 2907 | static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrInstructionErrName *instruction) { | 2940 | static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrInstructionErrName *instruction) { |
| 2908 | assert(g->generate_error_name_table); | 2941 | assert(g->generate_error_name_table); |
| 2909 | 2942 | ||
| 2910 | if (g->error_decls.length == 1) { | 2943 | if (g->errors_by_index.length == 1) { |
| 2911 | LLVMBuildUnreachable(g->builder); | 2944 | LLVMBuildUnreachable(g->builder); |
| 2912 | return nullptr; | 2945 | return nullptr; |
| 2913 | } | 2946 | } |
| ... | @@ -2915,7 +2948,7 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI | ... | @@ -2915,7 +2948,7 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI |
| 2915 | LLVMValueRef err_val = ir_llvm_value(g, instruction->value); | 2948 | LLVMValueRef err_val = ir_llvm_value(g, instruction->value); |
| 2916 | if (ir_want_runtime_safety(g, &instruction->base)) { | 2949 | if (ir_want_runtime_safety(g, &instruction->base)) { |
| 2917 | LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(err_val)); | 2950 | LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(err_val)); |
| 2918 | LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(err_val), g->error_decls.length, false); | 2951 | LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(err_val), g->errors_by_index.length, false); |
| 2919 | add_bounds_check(g, err_val, LLVMIntNE, zero, LLVMIntULT, end_val); | 2952 | add_bounds_check(g, err_val, LLVMIntNE, zero, LLVMIntULT, end_val); |
| 2920 | } | 2953 | } |
| 2921 | 2954 | ||
| ... | @@ -3393,11 +3426,11 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable, | ... | @@ -3393,11 +3426,11 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable, |
| 3393 | 3426 | ||
| 3394 | static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) { | 3427 | static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) { |
| 3395 | TypeTableEntry *err_union_type = instruction->value->value.type; | 3428 | TypeTableEntry *err_union_type = instruction->value->value.type; |
| 3396 | TypeTableEntry *child_type = err_union_type->data.error.child_type; | 3429 | TypeTableEntry *payload_type = err_union_type->data.error_union.payload_type; |
| 3397 | LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->value); | 3430 | LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->value); |
| 3398 | 3431 | ||
| 3399 | LLVMValueRef err_val; | 3432 | LLVMValueRef err_val; |
| 3400 | if (type_has_bits(child_type)) { | 3433 | if (type_has_bits(payload_type)) { |
| 3401 | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); | 3434 | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); |
| 3402 | err_val = gen_load_untyped(g, err_val_ptr, 0, false, ""); | 3435 | err_val = gen_load_untyped(g, err_val_ptr, 0, false, ""); |
| 3403 | } else { | 3436 | } else { |
| ... | @@ -3412,11 +3445,11 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab | ... | @@ -3412,11 +3445,11 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab |
| 3412 | TypeTableEntry *ptr_type = instruction->value->value.type; | 3445 | TypeTableEntry *ptr_type = instruction->value->value.type; |
| 3413 | assert(ptr_type->id == TypeTableEntryIdPointer); | 3446 | assert(ptr_type->id == TypeTableEntryIdPointer); |
| 3414 | TypeTableEntry *err_union_type = ptr_type->data.pointer.child_type; | 3447 | TypeTableEntry *err_union_type = ptr_type->data.pointer.child_type; |
| 3415 | TypeTableEntry *child_type = err_union_type->data.error.child_type; | 3448 | TypeTableEntry *payload_type = err_union_type->data.error_union.payload_type; |
| 3416 | LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); | 3449 | LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); |
| 3417 | LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); | 3450 | LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); |
| 3418 | 3451 | ||
| 3419 | if (type_has_bits(child_type)) { | 3452 | if (type_has_bits(payload_type)) { |
| 3420 | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); | 3453 | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); |
| 3421 | return gen_load_untyped(g, err_val_ptr, 0, false, ""); | 3454 | return gen_load_untyped(g, err_val_ptr, 0, false, ""); |
| 3422 | } else { | 3455 | } else { |
| ... | @@ -3428,13 +3461,17 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu | ... | @@ -3428,13 +3461,17 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu |
| 3428 | TypeTableEntry *ptr_type = instruction->value->value.type; | 3461 | TypeTableEntry *ptr_type = instruction->value->value.type; |
| 3429 | assert(ptr_type->id == TypeTableEntryIdPointer); | 3462 | assert(ptr_type->id == TypeTableEntryIdPointer); |
| 3430 | TypeTableEntry *err_union_type = ptr_type->data.pointer.child_type; | 3463 | TypeTableEntry *err_union_type = ptr_type->data.pointer.child_type; |
| 3431 | TypeTableEntry *child_type = err_union_type->data.error.child_type; | 3464 | TypeTableEntry *payload_type = err_union_type->data.error_union.payload_type; |
| 3432 | LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); | 3465 | LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); |
| 3433 | LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); | 3466 | LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); |
| 3434 | 3467 | ||
| 3435 | if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->error_decls.length > 1) { | 3468 | if (!type_has_bits(err_union_type->data.error_union.err_set_type)) { |
| 3469 | return err_union_handle; | ||
| 3470 | } | ||
| 3471 | |||
| 3472 | if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) { | ||
| 3436 | LLVMValueRef err_val; | 3473 | LLVMValueRef err_val; |
| 3437 | if (type_has_bits(child_type)) { | 3474 | if (type_has_bits(payload_type)) { |
| 3438 | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); | 3475 | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); |
| 3439 | err_val = gen_load_untyped(g, err_val_ptr, 0, false, ""); | 3476 | err_val = gen_load_untyped(g, err_val_ptr, 0, false, ""); |
| 3440 | } else { | 3477 | } else { |
| ... | @@ -3452,7 +3489,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu | ... | @@ -3452,7 +3489,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu |
| 3452 | LLVMPositionBuilderAtEnd(g->builder, ok_block); | 3489 | LLVMPositionBuilderAtEnd(g->builder, ok_block); |
| 3453 | } | 3490 | } |
| 3454 | 3491 | ||
| 3455 | if (type_has_bits(child_type)) { | 3492 | if (type_has_bits(payload_type)) { |
| 3456 | return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, ""); | 3493 | return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, ""); |
| 3457 | } else { | 3494 | } else { |
| 3458 | return nullptr; | 3495 | return nullptr; |
| ... | @@ -3493,10 +3530,12 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable | ... | @@ -3493,10 +3530,12 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable |
| 3493 | 3530 | ||
| 3494 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); | 3531 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); |
| 3495 | 3532 | ||
| 3496 | TypeTableEntry *child_type = wanted_type->data.error.child_type; | 3533 | TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type; |
| 3534 | TypeTableEntry *err_set_type = wanted_type->data.error_union.err_set_type; | ||
| 3535 | |||
| 3497 | LLVMValueRef err_val = ir_llvm_value(g, instruction->value); | 3536 | LLVMValueRef err_val = ir_llvm_value(g, instruction->value); |
| 3498 | 3537 | ||
| 3499 | if (!type_has_bits(child_type)) | 3538 | if (!type_has_bits(payload_type) || !type_has_bits(err_set_type)) |
| 3500 | return err_val; | 3539 | return err_val; |
| 3501 | 3540 | ||
| 3502 | assert(instruction->tmp_ptr); | 3541 | assert(instruction->tmp_ptr); |
| ... | @@ -3512,11 +3551,16 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa | ... | @@ -3512,11 +3551,16 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa |
| 3512 | 3551 | ||
| 3513 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); | 3552 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); |
| 3514 | 3553 | ||
| 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 | } | ||
| 3516 | 3560 | ||
| 3517 | LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref); | 3561 | LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref); |
| 3518 | 3562 | ||
| 3519 | if (!type_has_bits(child_type)) | 3563 | if (!type_has_bits(payload_type)) |
| 3520 | return ok_err_val; | 3564 | return ok_err_val; |
| 3521 | 3565 | ||
| 3522 | assert(instruction->tmp_ptr); | 3566 | assert(instruction->tmp_ptr); |
| ... | @@ -3527,7 +3571,7 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa | ... | @@ -3527,7 +3571,7 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa |
| 3527 | gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false); | 3571 | gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false); |
| 3528 | 3572 | ||
| 3529 | LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, ""); | 3573 | LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, ""); |
| 3530 | gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, child_type, false), payload_val); | 3574 | gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, payload_type, false), payload_val); |
| 3531 | 3575 | ||
| 3532 | return instruction->tmp_ptr; | 3576 | return instruction->tmp_ptr; |
| 3533 | } | 3577 | } |
| ... | @@ -3700,6 +3744,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -3700,6 +3744,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3700 | case IrInstructionIdArgType: | 3744 | case IrInstructionIdArgType: |
| 3701 | case IrInstructionIdTagType: | 3745 | case IrInstructionIdTagType: |
| 3702 | case IrInstructionIdExport: | 3746 | case IrInstructionIdExport: |
| 3747 | case IrInstructionIdErrorUnion: | ||
| 3703 | zig_unreachable(); | 3748 | zig_unreachable(); |
| 3704 | case IrInstructionIdReturn: | 3749 | case IrInstructionIdReturn: |
| 3705 | return ir_render_return(g, executable, (IrInstructionReturn *)instruction); | 3750 | return ir_render_return(g, executable, (IrInstructionReturn *)instruction); |
| ... | @@ -3933,7 +3978,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con | ... | @@ -3933,7 +3978,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con |
| 3933 | case TypeTableEntryIdUndefLit: | 3978 | case TypeTableEntryIdUndefLit: |
| 3934 | case TypeTableEntryIdNullLit: | 3979 | case TypeTableEntryIdNullLit: |
| 3935 | case TypeTableEntryIdErrorUnion: | 3980 | case TypeTableEntryIdErrorUnion: |
| 3936 | case TypeTableEntryIdPureError: | 3981 | case TypeTableEntryIdErrorSet: |
| 3937 | case TypeTableEntryIdNamespace: | 3982 | case TypeTableEntryIdNamespace: |
| 3938 | case TypeTableEntryIdBlock: | 3983 | case TypeTableEntryIdBlock: |
| 3939 | case TypeTableEntryIdBoundFn: | 3984 | case TypeTableEntryIdBoundFn: |
| ... | @@ -4026,10 +4071,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -4026,10 +4071,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 4026 | switch (type_entry->id) { | 4071 | switch (type_entry->id) { |
| 4027 | case TypeTableEntryIdInt: | 4072 | case TypeTableEntryIdInt: |
| 4028 | return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint); | 4073 | return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint); |
| 4029 | case TypeTableEntryIdPureError: | 4074 | case TypeTableEntryIdErrorSet: |
| 4030 | assert(const_val->data.x_pure_err); | 4075 | assert(const_val->data.x_err_set != nullptr); |
| 4031 | return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref, | 4076 | return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref, |
| 4032 | const_val->data.x_pure_err->value, false); | 4077 | const_val->data.x_err_set->value, false); |
| 4033 | case TypeTableEntryIdFloat: | 4078 | case TypeTableEntryIdFloat: |
| 4034 | switch (type_entry->data.floating.bit_count) { | 4079 | switch (type_entry->data.floating.bit_count) { |
| 4035 | case 32: | 4080 | case 32: |
| ... | @@ -4330,17 +4375,22 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -4330,17 +4375,22 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 4330 | } | 4375 | } |
| 4331 | case TypeTableEntryIdErrorUnion: | 4376 | case TypeTableEntryIdErrorUnion: |
| 4332 | { | 4377 | { |
| 4333 | TypeTableEntry *child_type = type_entry->data.error.child_type; | 4378 | TypeTableEntry *payload_type = type_entry->data.error_union.payload_type; |
| 4334 | if (!type_has_bits(child_type)) { | 4379 | TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type; |
| 4380 | if (!type_has_bits(payload_type)) { | ||
| 4381 | assert(type_has_bits(err_set_type)); | ||
| 4335 | uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0; | 4382 | uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0; |
| 4336 | return LLVMConstInt(g->err_tag_type->type_ref, value, false); | 4383 | return LLVMConstInt(g->err_tag_type->type_ref, value, false); |
| 4384 | } else if (!type_has_bits(err_set_type)) { | ||
| 4385 | assert(type_has_bits(payload_type)); | ||
| 4386 | return gen_const_val(g, const_val->data.x_err_union.payload); | ||
| 4337 | } else { | 4387 | } else { |
| 4338 | LLVMValueRef err_tag_value; | 4388 | LLVMValueRef err_tag_value; |
| 4339 | LLVMValueRef err_payload_value; | 4389 | LLVMValueRef err_payload_value; |
| 4340 | bool make_unnamed_struct; | 4390 | bool make_unnamed_struct; |
| 4341 | if (const_val->data.x_err_union.err) { | 4391 | if (const_val->data.x_err_union.err) { |
| 4342 | err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false); | 4392 | err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false); |
| 4343 | err_payload_value = LLVMConstNull(child_type->type_ref); | 4393 | err_payload_value = LLVMConstNull(payload_type->type_ref); |
| 4344 | make_unnamed_struct = false; | 4394 | make_unnamed_struct = false; |
| 4345 | } else { | 4395 | } else { |
| 4346 | err_tag_value = LLVMConstNull(g->err_tag_type->type_ref); | 4396 | err_tag_value = LLVMConstNull(g->err_tag_type->type_ref); |
| ... | @@ -4410,21 +4460,20 @@ static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const | ... | @@ -4410,21 +4460,20 @@ static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const |
| 4410 | } | 4460 | } |
| 4411 | 4461 | ||
| 4412 | static void generate_error_name_table(CodeGen *g) { | 4462 | static void generate_error_name_table(CodeGen *g) { |
| 4413 | if (g->err_name_table != nullptr || !g->generate_error_name_table || g->error_decls.length == 1) { | 4463 | if (g->err_name_table != nullptr || !g->generate_error_name_table || g->errors_by_index.length == 1) { |
| 4414 | return; | 4464 | return; |
| 4415 | } | 4465 | } |
| 4416 | 4466 | ||
| 4417 | assert(g->error_decls.length > 0); | 4467 | assert(g->errors_by_index.length > 0); |
| 4418 | 4468 | ||
| 4419 | TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); | 4469 | TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); |
| 4420 | TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type); | 4470 | TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type); |
| 4421 | 4471 | ||
| 4422 | LLVMValueRef *values = allocate<LLVMValueRef>(g->error_decls.length); | 4472 | LLVMValueRef *values = allocate<LLVMValueRef>(g->errors_by_index.length); |
| 4423 | values[0] = LLVMGetUndef(str_type->type_ref); | 4473 | values[0] = LLVMGetUndef(str_type->type_ref); |
| 4424 | for (size_t i = 1; i < g->error_decls.length; i += 1) { | 4474 | for (size_t i = 1; i < g->errors_by_index.length; i += 1) { |
| 4425 | AstNode *error_decl_node = g->error_decls.at(i); | 4475 | ErrorTableEntry *err_entry = g->errors_by_index.at(i); |
| 4426 | assert(error_decl_node->type == NodeTypeErrorValueDecl); | 4476 | Buf *name = &err_entry->name; |
| 4427 | Buf *name = error_decl_node->data.error_value_decl.name; | ||
| 4428 | 4477 | ||
| 4429 | g->largest_err_name_len = max(g->largest_err_name_len, buf_len(name)); | 4478 | g->largest_err_name_len = max(g->largest_err_name_len, buf_len(name)); |
| 4430 | 4479 | ||
| ... | @@ -4443,7 +4492,7 @@ static void generate_error_name_table(CodeGen *g) { | ... | @@ -4443,7 +4492,7 @@ static void generate_error_name_table(CodeGen *g) { |
| 4443 | values[i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2); | 4492 | values[i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2); |
| 4444 | } | 4493 | } |
| 4445 | 4494 | ||
| 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); |
| 4447 | 4496 | ||
| 4448 | g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init), | 4497 | g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init), |
| 4449 | buf_ptr(get_mangled_name(g, buf_create_from_str("__zig_err_name_table"), false))); | 4498 | buf_ptr(get_mangled_name(g, buf_create_from_str("__zig_err_name_table"), false))); |
| ... | @@ -4575,6 +4624,28 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -4575,6 +4624,28 @@ static void do_code_gen(CodeGen *g) { |
| 4575 | 4624 | ||
| 4576 | codegen_add_time_event(g, "Code Generation"); | 4625 | codegen_add_time_event(g, "Code Generation"); |
| 4577 | 4626 | ||
| 4627 | { | ||
| 4628 | // create debug type for error sets | ||
| 4629 | assert(g->err_enumerators.length == g->errors_by_index.length); | ||
| 4630 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, g->err_tag_type->type_ref); | ||
| 4631 | uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, g->err_tag_type->type_ref); | ||
| 4632 | ZigLLVMDIFile *err_set_di_file = nullptr; | ||
| 4633 | ZigLLVMDIType *err_set_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, | ||
| 4634 | ZigLLVMCompileUnitToScope(g->compile_unit), buf_ptr(&g->builtin_types.entry_global_error_set->name), | ||
| 4635 | err_set_di_file, 0, | ||
| 4636 | tag_debug_size_in_bits, | ||
| 4637 | tag_debug_align_in_bits, | ||
| 4638 | g->err_enumerators.items, g->err_enumerators.length, | ||
| 4639 | g->err_tag_type->di_type, ""); | ||
| 4640 | ZigLLVMReplaceTemporary(g->dbuilder, g->builtin_types.entry_global_error_set->di_type, err_set_di_type); | ||
| 4641 | g->builtin_types.entry_global_error_set->di_type = err_set_di_type; | ||
| 4642 | |||
| 4643 | for (size_t i = 0; i < g->error_di_types.length; i += 1) { | ||
| 4644 | ZigLLVMDIType **di_type_ptr = g->error_di_types.at(i); | ||
| 4645 | *di_type_ptr = err_set_di_type; | ||
| 4646 | } | ||
| 4647 | } | ||
| 4648 | |||
| 4578 | generate_error_name_table(g); | 4649 | generate_error_name_table(g); |
| 4579 | generate_enum_name_tables(g); | 4650 | generate_enum_name_tables(g); |
| 4580 | 4651 | ||
| ... | @@ -5176,16 +5247,24 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -5176,16 +5247,24 @@ static void define_builtin_types(CodeGen *g) { |
| 5176 | } | 5247 | } |
| 5177 | 5248 | ||
| 5178 | { | 5249 | { |
| 5179 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError); | 5250 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorSet); |
| 5180 | buf_init_from_str(&entry->name, "error"); | 5251 | buf_init_from_str(&entry->name, "error"); |
| 5252 | entry->data.error_set.err_count = UINT32_MAX; | ||
| 5181 | 5253 | ||
| 5182 | // TODO allow overriding this type and keep track of max value and emit an | 5254 | // TODO allow overriding this type and keep track of max value and emit an |
| 5183 | // error if there are too many errors declared | 5255 | // error if there are too many errors declared |
| 5184 | g->err_tag_type = g->builtin_types.entry_u16; | 5256 | g->err_tag_type = g->builtin_types.entry_u16; |
| 5185 | 5257 | ||
| 5186 | g->builtin_types.entry_pure_error = entry; | 5258 | g->builtin_types.entry_global_error_set = entry; |
| 5187 | entry->type_ref = g->err_tag_type->type_ref; | 5259 | entry->type_ref = g->err_tag_type->type_ref; |
| 5188 | entry->di_type = g->err_tag_type->di_type; | 5260 | |
| 5261 | entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, | ||
| 5262 | ZigLLVMTag_DW_enumeration_type(), "error", | ||
| 5263 | ZigLLVMCompileUnitToScope(g->compile_unit), nullptr, 0); | ||
| 5264 | |||
| 5265 | // reserve index 0 to indicate no error | ||
| 5266 | g->err_enumerators.append(ZigLLVMCreateDebugEnumerator(g->dbuilder, "(none)", 0)); | ||
| 5267 | g->errors_by_index.append(nullptr); | ||
| 5189 | 5268 | ||
| 5190 | g->primitive_type_table.put(&entry->name, entry); | 5269 | g->primitive_type_table.put(&entry->name, entry); |
| 5191 | } | 5270 | } |
| ... | @@ -5815,7 +5894,7 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry | ... | @@ -5815,7 +5894,7 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry |
| 5815 | case TypeTableEntryIdBoundFn: | 5894 | case TypeTableEntryIdBoundFn: |
| 5816 | case TypeTableEntryIdArgTuple: | 5895 | case TypeTableEntryIdArgTuple: |
| 5817 | case TypeTableEntryIdErrorUnion: | 5896 | case TypeTableEntryIdErrorUnion: |
| 5818 | case TypeTableEntryIdPureError: | 5897 | case TypeTableEntryIdErrorSet: |
| 5819 | zig_unreachable(); | 5898 | zig_unreachable(); |
| 5820 | case TypeTableEntryIdVoid: | 5899 | case TypeTableEntryIdVoid: |
| 5821 | case TypeTableEntryIdUnreachable: | 5900 | case TypeTableEntryIdUnreachable: |
| ... | @@ -5988,7 +6067,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf | ... | @@ -5988,7 +6067,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf |
| 5988 | return; | 6067 | return; |
| 5989 | } | 6068 | } |
| 5990 | case TypeTableEntryIdErrorUnion: | 6069 | case TypeTableEntryIdErrorUnion: |
| 5991 | case TypeTableEntryIdPureError: | 6070 | case TypeTableEntryIdErrorSet: |
| 5992 | case TypeTableEntryIdFn: | 6071 | case TypeTableEntryIdFn: |
| 5993 | zig_panic("TODO implement get_c_type for more types"); | 6072 | zig_panic("TODO implement get_c_type for more types"); |
| 5994 | case TypeTableEntryIdInvalid: | 6073 | case TypeTableEntryIdInvalid: |
| ... | @@ -6155,7 +6234,7 @@ static void gen_h_file(CodeGen *g) { | ... | @@ -6155,7 +6234,7 @@ static void gen_h_file(CodeGen *g) { |
| 6155 | case TypeTableEntryIdUndefLit: | 6234 | case TypeTableEntryIdUndefLit: |
| 6156 | case TypeTableEntryIdNullLit: | 6235 | case TypeTableEntryIdNullLit: |
| 6157 | case TypeTableEntryIdErrorUnion: | 6236 | case TypeTableEntryIdErrorUnion: |
| 6158 | case TypeTableEntryIdPureError: | 6237 | case TypeTableEntryIdErrorSet: |
| 6159 | case TypeTableEntryIdNamespace: | 6238 | case TypeTableEntryIdNamespace: |
| 6160 | case TypeTableEntryIdBlock: | 6239 | case TypeTableEntryIdBlock: |
| 6161 | case TypeTableEntryIdBoundFn: | 6240 | case TypeTableEntryIdBoundFn: |
| ... | @@ -6265,3 +6344,4 @@ PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, | ... | @@ -6265,3 +6344,4 @@ PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, |
| 6265 | } | 6344 | } |
| 6266 | return pkg; | 6345 | return pkg; |
| 6267 | } | 6346 | } |
| 6347 |
src/codegen.hpp+1| ... | @@ -36,6 +36,7 @@ void codegen_set_kernel32_lib_dir(CodeGen *codegen, Buf *kernel32_lib_dir); | ... | @@ -36,6 +36,7 @@ void codegen_set_kernel32_lib_dir(CodeGen *codegen, Buf *kernel32_lib_dir); |
| 36 | void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker); | 36 | void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker); |
| 37 | void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole); | 37 | void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole); |
| 38 | void codegen_add_lib_dir(CodeGen *codegen, const char *dir); | 38 | void codegen_add_lib_dir(CodeGen *codegen, const char *dir); |
| 39 | void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib); | ||
| 39 | LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib); | 40 | LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib); |
| 40 | void codegen_add_framework(CodeGen *codegen, const char *name); | 41 | void codegen_add_framework(CodeGen *codegen, const char *name); |
| 41 | void codegen_add_rpath(CodeGen *codegen, const char *name); | 42 | void codegen_add_rpath(CodeGen *codegen, const char *name); |
src/ir.cpp+1428-232| ... | @@ -45,6 +45,59 @@ static LVal make_lval_addr(bool is_const, bool is_volatile) { | ... | @@ -45,6 +45,59 @@ static LVal make_lval_addr(bool is_const, bool is_volatile) { |
| 45 | return { true, is_const, is_volatile }; | 45 | return { true, is_const, is_volatile }; |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | enum 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 | |||
| 70 | struct ConstCastErrSetMismatch { | ||
| 71 | ZigList<ErrorTableEntry *> missing_errors; | ||
| 72 | }; | ||
| 73 | |||
| 74 | struct ConstCastOnly; | ||
| 75 | |||
| 76 | struct ConstCastArg { | ||
| 77 | size_t arg_index; | ||
| 78 | ConstCastOnly *child; | ||
| 79 | }; | ||
| 80 | |||
| 81 | struct ConstCastArgNoAlias { | ||
| 82 | size_t arg_index; | ||
| 83 | }; | ||
| 84 | |||
| 85 | struct 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 | |||
| 48 | static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); | 101 | static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); |
| 49 | static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval); | 102 | static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval); |
| 50 | static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction); | 103 | static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction); |
| ... | @@ -580,6 +633,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorReturnTrace | ... | @@ -580,6 +633,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorReturnTrace |
| 580 | return IrInstructionIdErrorReturnTrace; | 633 | return IrInstructionIdErrorReturnTrace; |
| 581 | } | 634 | } |
| 582 | 635 | ||
| 636 | static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnion *) { | ||
| 637 | return IrInstructionIdErrorUnion; | ||
| 638 | } | ||
| 639 | |||
| 583 | template<typename T> | 640 | template<typename T> |
| 584 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { | 641 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 585 | T *special_instruction = allocate<T>(1); | 642 | T *special_instruction = allocate<T>(1); |
| ... | @@ -2326,6 +2383,19 @@ static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, | ... | @@ -2326,6 +2383,19 @@ static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, |
| 2326 | return &instruction->base; | 2383 | return &instruction->base; |
| 2327 | } | 2384 | } |
| 2328 | 2385 | ||
| 2386 | static 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 | |||
| 2329 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { | 2399 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 2330 | results[ReturnKindUnconditional] = 0; | 2400 | results[ReturnKindUnconditional] = 0; |
| 2331 | results[ReturnKindError] = 0; | 2401 | results[ReturnKindError] = 0; |
| ... | @@ -2800,6 +2870,23 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As | ... | @@ -2800,6 +2870,23 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As |
| 2800 | return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values); | 2870 | return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values); |
| 2801 | } | 2871 | } |
| 2802 | 2872 | ||
| 2873 | static 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 | |||
| 2803 | static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) { | 2890 | static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 2804 | assert(node->type == NodeTypeBinOpExpr); | 2891 | assert(node->type == NodeTypeBinOpExpr); |
| 2805 | 2892 | ||
| ... | @@ -2835,10 +2922,8 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) | ... | @@ -2835,10 +2922,8 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) |
| 2835 | return ir_gen_assign_op(irb, scope, node, IrBinOpBinXor); | 2922 | return ir_gen_assign_op(irb, scope, node, IrBinOpBinXor); |
| 2836 | case BinOpTypeAssignBitOr: | 2923 | case BinOpTypeAssignBitOr: |
| 2837 | return ir_gen_assign_op(irb, scope, node, IrBinOpBinOr); | 2924 | return ir_gen_assign_op(irb, scope, node, IrBinOpBinOr); |
| 2838 | case BinOpTypeAssignBoolAnd: | 2925 | case BinOpTypeAssignMergeErrorSets: |
| 2839 | return ir_gen_assign_op(irb, scope, node, IrBinOpBoolAnd); | 2926 | return ir_gen_assign_op(irb, scope, node, IrBinOpMergeErrorSets); |
| 2840 | case BinOpTypeAssignBoolOr: | ||
| 2841 | return ir_gen_assign_op(irb, scope, node, IrBinOpBoolOr); | ||
| 2842 | case BinOpTypeBoolOr: | 2927 | case BinOpTypeBoolOr: |
| 2843 | return ir_gen_bool_or(irb, scope, node); | 2928 | return ir_gen_bool_or(irb, scope, node); |
| 2844 | case BinOpTypeBoolAnd: | 2929 | case BinOpTypeBoolAnd: |
| ... | @@ -2885,8 +2970,12 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) | ... | @@ -2885,8 +2970,12 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) |
| 2885 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat); | 2970 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat); |
| 2886 | case BinOpTypeArrayMult: | 2971 | case BinOpTypeArrayMult: |
| 2887 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult); | 2972 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult); |
| 2973 | case BinOpTypeMergeErrorSets: | ||
| 2974 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets); | ||
| 2888 | case BinOpTypeUnwrapMaybe: | 2975 | case BinOpTypeUnwrapMaybe: |
| 2889 | return ir_gen_maybe_ok_or(irb, scope, node); | 2976 | return ir_gen_maybe_ok_or(irb, scope, node); |
| 2977 | case BinOpTypeErrorUnion: | ||
| 2978 | return ir_gen_error_union(irb, scope, node); | ||
| 2890 | } | 2979 | } |
| 2891 | zig_unreachable(); | 2980 | zig_unreachable(); |
| 2892 | } | 2981 | } |
| ... | @@ -3990,8 +4079,6 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod | ... | @@ -3990,8 +4079,6 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod |
| 3990 | return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval); | 4079 | return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval); |
| 3991 | case PrefixOpMaybe: | 4080 | case PrefixOpMaybe: |
| 3992 | return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe), lval); | 4081 | return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe), lval); |
| 3993 | case PrefixOpError: | ||
| 3994 | return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpError), lval); | ||
| 3995 | case PrefixOpUnwrapMaybe: | 4082 | case PrefixOpUnwrapMaybe: |
| 3996 | return ir_gen_maybe_assert_ok(irb, scope, node, lval); | 4083 | return ir_gen_maybe_assert_ok(irb, scope, node, lval); |
| 3997 | } | 4084 | } |
| ... | @@ -4713,12 +4800,8 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -4713,12 +4800,8 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 4713 | IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse"); | 4800 | IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse"); |
| 4714 | IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "TryEnd"); | 4801 | IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "TryEnd"); |
| 4715 | 4802 | ||
| 4716 | IrInstruction *is_comptime; | 4803 | bool force_comptime = ir_should_inline(irb->exec, scope); |
| 4717 | if (ir_should_inline(irb->exec, scope)) { | 4804 | IrInstruction *is_comptime = force_comptime ? ir_build_const_bool(irb, scope, node, true) : ir_build_test_comptime(irb, scope, node, is_err); |
| 4718 | is_comptime = ir_build_const_bool(irb, scope, node, true); | ||
| 4719 | } else { | ||
| 4720 | is_comptime = ir_build_test_comptime(irb, scope, node, is_err); | ||
| 4721 | } | ||
| 4722 | ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime); | 4805 | ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime); |
| 4723 | 4806 | ||
| 4724 | ir_set_cursor_at_end_and_append_block(irb, ok_block); | 4807 | ir_set_cursor_at_end_and_append_block(irb, ok_block); |
| ... | @@ -4727,8 +4810,9 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -4727,8 +4810,9 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 4727 | if (var_symbol) { | 4810 | if (var_symbol) { |
| 4728 | IrInstruction *var_type = nullptr; | 4811 | IrInstruction *var_type = nullptr; |
| 4729 | bool is_shadowable = false; | 4812 | bool is_shadowable = false; |
| 4813 | IrInstruction *var_is_comptime = force_comptime ? ir_build_const_bool(irb, scope, node, true) : ir_build_test_comptime(irb, scope, node, err_val); | ||
| 4730 | VariableTableEntry *var = ir_create_var(irb, node, scope, | 4814 | VariableTableEntry *var = ir_create_var(irb, node, scope, |
| 4731 | var_symbol, var_is_const, var_is_const, is_shadowable, is_comptime); | 4815 | var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime); |
| 4732 | 4816 | ||
| 4733 | IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, scope, node, err_val_ptr, false); | 4817 | IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, scope, node, err_val_ptr, false); |
| 4734 | IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, node, var_ptr_value); | 4818 | IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, node, var_ptr_value); |
| ... | @@ -5165,7 +5249,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast | ... | @@ -5165,7 +5249,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast |
| 5165 | 5249 | ||
| 5166 | static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) { | 5250 | static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 5167 | assert(node->type == NodeTypeErrorType); | 5251 | assert(node->type == NodeTypeErrorType); |
| 5168 | return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_pure_error); | 5252 | return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_global_error_set); |
| 5169 | } | 5253 | } |
| 5170 | 5254 | ||
| 5171 | static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode *node) { | 5255 | static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |
| ... | @@ -5249,8 +5333,6 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN | ... | @@ -5249,8 +5333,6 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN |
| 5249 | Scope *err_scope; | 5333 | Scope *err_scope; |
| 5250 | if (var_node) { | 5334 | if (var_node) { |
| 5251 | assert(var_node->type == NodeTypeSymbol); | 5335 | assert(var_node->type == NodeTypeSymbol); |
| 5252 | IrInstruction *var_type = ir_build_const_type(irb, parent_scope, node, | ||
| 5253 | irb->codegen->builtin_types.entry_pure_error); | ||
| 5254 | Buf *var_name = var_node->data.symbol_expr.symbol; | 5336 | Buf *var_name = var_node->data.symbol_expr.symbol; |
| 5255 | bool is_const = true; | 5337 | bool is_const = true; |
| 5256 | bool is_shadowable = false; | 5338 | bool is_shadowable = false; |
| ... | @@ -5258,7 +5340,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN | ... | @@ -5258,7 +5340,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN |
| 5258 | is_const, is_const, is_shadowable, is_comptime); | 5340 | is_const, is_const, is_shadowable, is_comptime); |
| 5259 | err_scope = var->child_scope; | 5341 | err_scope = var->child_scope; |
| 5260 | IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr); | 5342 | IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr); |
| 5261 | ir_build_var_decl(irb, err_scope, var_node, var, var_type, nullptr, err_val); | 5343 | ir_build_var_decl(irb, err_scope, var_node, var, nullptr, nullptr, err_val); |
| 5262 | } else { | 5344 | } else { |
| 5263 | err_scope = parent_scope; | 5345 | err_scope = parent_scope; |
| 5264 | } | 5346 | } |
| ... | @@ -5348,6 +5430,135 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope, | ... | @@ -5348,6 +5430,135 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope, |
| 5348 | return ir_build_const_type(irb, parent_scope, node, container_type); | 5430 | return ir_build_const_type(irb, parent_scope, node, container_type); |
| 5349 | } | 5431 | } |
| 5350 | 5432 | ||
| 5433 | // errors should be populated with set1's values | ||
| 5434 | static 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 | |||
| 5487 | static 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 | |||
| 5506 | static 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 | |||
| 5351 | static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNode *node) { | 5562 | static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |
| 5352 | assert(node->type == NodeTypeFnProto); | 5563 | assert(node->type == NodeTypeFnProto); |
| 5353 | 5564 | ||
| ... | @@ -5401,7 +5612,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop | ... | @@ -5401,7 +5612,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 5401 | case NodeTypeStructField: | 5612 | case NodeTypeStructField: |
| 5402 | case NodeTypeFnDef: | 5613 | case NodeTypeFnDef: |
| 5403 | case NodeTypeFnDecl: | 5614 | case NodeTypeFnDecl: |
| 5404 | case NodeTypeErrorValueDecl: | ||
| 5405 | case NodeTypeTestDecl: | 5615 | case NodeTypeTestDecl: |
| 5406 | zig_unreachable(); | 5616 | zig_unreachable(); |
| 5407 | case NodeTypeBlock: | 5617 | case NodeTypeBlock: |
| ... | @@ -5482,6 +5692,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop | ... | @@ -5482,6 +5692,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 5482 | return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); | 5692 | return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); |
| 5483 | case NodeTypeFnProto: | 5693 | case NodeTypeFnProto: |
| 5484 | return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval); | 5694 | return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval); |
| 5695 | case NodeTypeErrorSetDecl: | ||
| 5696 | return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval); | ||
| 5485 | } | 5697 | } |
| 5486 | zig_unreachable(); | 5698 | zig_unreachable(); |
| 5487 | } | 5699 | } |
| ... | @@ -6287,6 +6499,274 @@ static bool slice_is_const(TypeTableEntry *type) { | ... | @@ -6287,6 +6499,274 @@ static bool slice_is_const(TypeTableEntry *type) { |
| 6287 | return type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const; | 6499 | return type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const; |
| 6288 | } | 6500 | } |
| 6289 | 6501 | ||
| 6502 | static 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 | |||
| 6524 | static 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 | |||
| 6579 | static 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 | |||
| 6290 | enum ImplicitCastMatchResult { | 6770 | enum ImplicitCastMatchResult { |
| 6291 | ImplicitCastMatchResultNo, | 6771 | ImplicitCastMatchResultNo, |
| 6292 | ImplicitCastMatchResultYes, | 6772 | ImplicitCastMatchResultYes, |
| ... | @@ -6296,10 +6776,46 @@ enum ImplicitCastMatchResult { | ... | @@ -6296,10 +6776,46 @@ enum ImplicitCastMatchResult { |
| 6296 | static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, TypeTableEntry *expected_type, | 6776 | static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, TypeTableEntry *expected_type, |
| 6297 | TypeTableEntry *actual_type, IrInstruction *value) | 6777 | TypeTableEntry *actual_type, IrInstruction *value) |
| 6298 | { | 6778 | { |
| 6299 | if (types_match_const_cast_only(expected_type, actual_type)) { | 6779 | AstNode *source_node = value->source_node; |
| 6780 | ConstCastOnly const_cast_result = types_match_const_cast_only(ira, expected_type, actual_type, source_node); | ||
| 6781 | if (const_cast_result.id == ConstCastResultIdOk) { | ||
| 6300 | return ImplicitCastMatchResultYes; | 6782 | return ImplicitCastMatchResultYes; |
| 6301 | } | 6783 | } |
| 6302 | 6784 | ||
| 6785 | // if we got here with error sets, make an error showing the incompatibilities | ||
| 6786 | ZigList<ErrorTableEntry *> *missing_errors = nullptr; | ||
| 6787 | if (const_cast_result.id == ConstCastResultIdErrSet) { | ||
| 6788 | missing_errors = &const_cast_result.data.error_set.missing_errors; | ||
| 6789 | } | ||
| 6790 | if (const_cast_result.id == ConstCastResultIdErrorUnionErrorSet) { | ||
| 6791 | if (const_cast_result.data.error_union_error_set->id == ConstCastResultIdErrSet) { | ||
| 6792 | missing_errors = &const_cast_result.data.error_union_error_set->data.error_set.missing_errors; | ||
| 6793 | } else if (const_cast_result.data.error_union_error_set->id == ConstCastResultIdErrSetGlobal) { | ||
| 6794 | ErrorMsg *msg = ir_add_error(ira, value, | ||
| 6795 | buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name))); | ||
| 6796 | add_error_note(ira->codegen, msg, value->source_node, | ||
| 6797 | buf_sprintf("unable to cast global error set into smaller set")); | ||
| 6798 | return ImplicitCastMatchResultReportedError; | ||
| 6799 | } | ||
| 6800 | } else if (const_cast_result.id == ConstCastResultIdErrSetGlobal) { | ||
| 6801 | ErrorMsg *msg = ir_add_error(ira, value, | ||
| 6802 | buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name))); | ||
| 6803 | add_error_note(ira->codegen, msg, value->source_node, | ||
| 6804 | buf_sprintf("unable to cast global error set into smaller set")); | ||
| 6805 | return ImplicitCastMatchResultReportedError; | ||
| 6806 | } | ||
| 6807 | if (missing_errors != nullptr) { | ||
| 6808 | ErrorMsg *msg = ir_add_error(ira, value, | ||
| 6809 | buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name))); | ||
| 6810 | for (size_t i = 0; i < missing_errors->length; i += 1) { | ||
| 6811 | ErrorTableEntry *error_entry = missing_errors->at(i); | ||
| 6812 | add_error_note(ira->codegen, msg, error_entry->decl_node, | ||
| 6813 | buf_sprintf("'error.%s' not a member of destination error set", buf_ptr(&error_entry->name))); | ||
| 6814 | } | ||
| 6815 | |||
| 6816 | return ImplicitCastMatchResultReportedError; | ||
| 6817 | } | ||
| 6818 | |||
| 6303 | // implicit conversion from anything to var | 6819 | // implicit conversion from anything to var |
| 6304 | if (expected_type->id == TypeTableEntryIdVar) { | 6820 | if (expected_type->id == TypeTableEntryIdVar) { |
| 6305 | return ImplicitCastMatchResultYes; | 6821 | return ImplicitCastMatchResultYes; |
| ... | @@ -6319,25 +6835,25 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, | ... | @@ -6319,25 +6835,25 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, |
| 6319 | return ImplicitCastMatchResultYes; | 6835 | return ImplicitCastMatchResultYes; |
| 6320 | } | 6836 | } |
| 6321 | 6837 | ||
| 6322 | // implicit T to %T | 6838 | // implicit T to U!T |
| 6323 | if (expected_type->id == TypeTableEntryIdErrorUnion && | 6839 | if (expected_type->id == TypeTableEntryIdErrorUnion && |
| 6324 | ir_types_match_with_implicit_cast(ira, expected_type->data.error.child_type, actual_type, value)) | 6840 | ir_types_match_with_implicit_cast(ira, expected_type->data.error_union.payload_type, actual_type, value)) |
| 6325 | { | 6841 | { |
| 6326 | return ImplicitCastMatchResultYes; | 6842 | return ImplicitCastMatchResultYes; |
| 6327 | } | 6843 | } |
| 6328 | 6844 | ||
| 6329 | // implicit conversion from pure error to error union type | 6845 | // implicit conversion from error set to error union type |
| 6330 | if (expected_type->id == TypeTableEntryIdErrorUnion && | 6846 | if (expected_type->id == TypeTableEntryIdErrorUnion && |
| 6331 | actual_type->id == TypeTableEntryIdPureError) | 6847 | actual_type->id == TypeTableEntryIdErrorSet) |
| 6332 | { | 6848 | { |
| 6333 | return ImplicitCastMatchResultYes; | 6849 | return ImplicitCastMatchResultYes; |
| 6334 | } | 6850 | } |
| 6335 | 6851 | ||
| 6336 | // implicit conversion from T to %?T | 6852 | // implicit conversion from T to U!?T |
| 6337 | if (expected_type->id == TypeTableEntryIdErrorUnion && | 6853 | if (expected_type->id == TypeTableEntryIdErrorUnion && |
| 6338 | expected_type->data.error.child_type->id == TypeTableEntryIdMaybe && | 6854 | expected_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe && |
| 6339 | ir_types_match_with_implicit_cast(ira, | 6855 | ir_types_match_with_implicit_cast(ira, |
| 6340 | expected_type->data.error.child_type->data.maybe.child_type, | 6856 | expected_type->data.error_union.payload_type->data.maybe.child_type, |
| 6341 | actual_type, value)) | 6857 | actual_type, value)) |
| 6342 | { | 6858 | { |
| 6343 | return ImplicitCastMatchResultYes; | 6859 | return ImplicitCastMatchResultYes; |
| ... | @@ -6374,7 +6890,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, | ... | @@ -6374,7 +6890,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, |
| 6374 | assert(ptr_type->id == TypeTableEntryIdPointer); | 6890 | assert(ptr_type->id == TypeTableEntryIdPointer); |
| 6375 | 6891 | ||
| 6376 | if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && | 6892 | if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && |
| 6377 | types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) | 6893 | types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk) |
| 6378 | { | 6894 | { |
| 6379 | return ImplicitCastMatchResultYes; | 6895 | return ImplicitCastMatchResultYes; |
| 6380 | } | 6896 | } |
| ... | @@ -6392,7 +6908,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, | ... | @@ -6392,7 +6908,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, |
| 6392 | TypeTableEntry *array_type = actual_type->data.pointer.child_type; | 6908 | TypeTableEntry *array_type = actual_type->data.pointer.child_type; |
| 6393 | 6909 | ||
| 6394 | if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) && | 6910 | if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) && |
| 6395 | types_match_const_cast_only(ptr_type->data.pointer.child_type, array_type->data.array.child_type)) | 6911 | types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type, source_node).id == ConstCastResultIdOk) |
| 6396 | { | 6912 | { |
| 6397 | return ImplicitCastMatchResultYes; | 6913 | return ImplicitCastMatchResultYes; |
| 6398 | } | 6914 | } |
| ... | @@ -6408,7 +6924,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, | ... | @@ -6408,7 +6924,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, |
| 6408 | expected_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry; | 6924 | expected_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry; |
| 6409 | assert(ptr_type->id == TypeTableEntryIdPointer); | 6925 | assert(ptr_type->id == TypeTableEntryIdPointer); |
| 6410 | if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && | 6926 | if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && |
| 6411 | types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) | 6927 | types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk) |
| 6412 | { | 6928 | { |
| 6413 | return ImplicitCastMatchResultYes; | 6929 | return ImplicitCastMatchResultYes; |
| 6414 | } | 6930 | } |
| ... | @@ -6423,7 +6939,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, | ... | @@ -6423,7 +6939,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, |
| 6423 | expected_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry; | 6939 | expected_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry; |
| 6424 | assert(ptr_type->id == TypeTableEntryIdPointer); | 6940 | assert(ptr_type->id == TypeTableEntryIdPointer); |
| 6425 | if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && | 6941 | if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && |
| 6426 | types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) | 6942 | types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk) |
| 6427 | { | 6943 | { |
| 6428 | return ImplicitCastMatchResultYes; | 6944 | return ImplicitCastMatchResultYes; |
| 6429 | } | 6945 | } |
| ... | @@ -6503,7 +7019,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, | ... | @@ -6503,7 +7019,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, |
| 6503 | // implicitly take a const pointer to something | 7019 | // implicitly take a const pointer to something |
| 6504 | if (!type_requires_comptime(actual_type)) { | 7020 | if (!type_requires_comptime(actual_type)) { |
| 6505 | TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true); | 7021 | TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true); |
| 6506 | if (types_match_const_cast_only(expected_type, const_ptr_actual)) { | 7022 | if (types_match_const_cast_only(ira, expected_type, const_ptr_actual, source_node).id == ConstCastResultIdOk) { |
| 6507 | return ImplicitCastMatchResultYes; | 7023 | return ImplicitCastMatchResultYes; |
| 6508 | } | 7024 | } |
| 6509 | } | 7025 | } |
| ... | @@ -6511,13 +7027,39 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, | ... | @@ -6511,13 +7027,39 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, |
| 6511 | return ImplicitCastMatchResultNo; | 7027 | return ImplicitCastMatchResultNo; |
| 6512 | } | 7028 | } |
| 6513 | 7029 | ||
| 7030 | static 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 | |||
| 6514 | static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) { | 7036 | static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) { |
| 6515 | assert(instruction_count >= 1); | 7037 | assert(instruction_count >= 1); |
| 6516 | IrInstruction *prev_inst = instructions[0]; | 7038 | IrInstruction *prev_inst = instructions[0]; |
| 6517 | if (type_is_invalid(prev_inst->value.type)) { | 7039 | if (type_is_invalid(prev_inst->value.type)) { |
| 6518 | return ira->codegen->builtin_types.entry_invalid; | 7040 | return ira->codegen->builtin_types.entry_invalid; |
| 6519 | } | 7041 | } |
| 6520 | bool any_are_pure_error = (prev_inst->value.type->id == TypeTableEntryIdPureError); | 7042 | ErrorTableEntry **errors = nullptr; |
| 7043 | size_t errors_count = 0; | ||
| 7044 | TypeTableEntry *err_set_type = nullptr; | ||
| 7045 | if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) { | ||
| 7046 | if (type_is_global_error_set(prev_inst->value.type)) { | ||
| 7047 | err_set_type = ira->codegen->builtin_types.entry_global_error_set; | ||
| 7048 | } else { | ||
| 7049 | err_set_type = prev_inst->value.type; | ||
| 7050 | if (!resolve_inferred_error_set(ira, err_set_type, prev_inst->source_node)) { | ||
| 7051 | return ira->codegen->builtin_types.entry_invalid; | ||
| 7052 | } | ||
| 7053 | update_errors_helper(ira->codegen, &errors, &errors_count); | ||
| 7054 | |||
| 7055 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | ||
| 7056 | ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; | ||
| 7057 | assert(errors[error_entry->value] == nullptr); | ||
| 7058 | errors[error_entry->value] = error_entry; | ||
| 7059 | } | ||
| 7060 | } | ||
| 7061 | } | ||
| 7062 | |||
| 6521 | bool any_are_null = (prev_inst->value.type->id == TypeTableEntryIdNullLit); | 7063 | bool any_are_null = (prev_inst->value.type->id == TypeTableEntryIdNullLit); |
| 6522 | bool convert_to_const_slice = false; | 7064 | bool convert_to_const_slice = false; |
| 6523 | for (size_t i = 1; i < instruction_count; i += 1) { | 7065 | for (size_t i = 1; i < instruction_count; i += 1) { |
| ... | @@ -6538,34 +7080,280 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -6538,34 +7080,280 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 6538 | continue; | 7080 | continue; |
| 6539 | } | 7081 | } |
| 6540 | 7082 | ||
| 6541 | if (prev_type->id == TypeTableEntryIdPureError) { | 7083 | if (prev_type->id == TypeTableEntryIdNullLit) { |
| 6542 | prev_inst = cur_inst; | 7084 | prev_inst = cur_inst; |
| 6543 | continue; | 7085 | continue; |
| 6544 | } | 7086 | } |
| 6545 | 7087 | ||
| 6546 | if (prev_type->id == TypeTableEntryIdNullLit) { | 7088 | if (cur_type->id == TypeTableEntryIdNullLit) { |
| 6547 | prev_inst = cur_inst; | 7089 | any_are_null = true; |
| 6548 | continue; | 7090 | continue; |
| 6549 | } | 7091 | } |
| 6550 | 7092 | ||
| 6551 | if (cur_type->id == TypeTableEntryIdPureError) { | 7093 | if (prev_type->id == TypeTableEntryIdErrorSet) { |
| 7094 | assert(err_set_type != nullptr); | ||
| 7095 | if (cur_type->id == TypeTableEntryIdErrorSet) { | ||
| 7096 | if (type_is_global_error_set(err_set_type)) { | ||
| 7097 | continue; | ||
| 7098 | } | ||
| 7099 | if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) { | ||
| 7100 | return ira->codegen->builtin_types.entry_invalid; | ||
| 7101 | } | ||
| 7102 | if (type_is_global_error_set(cur_type)) { | ||
| 7103 | err_set_type = ira->codegen->builtin_types.entry_global_error_set; | ||
| 7104 | prev_inst = cur_inst; | ||
| 7105 | continue; | ||
| 7106 | } | ||
| 7107 | |||
| 7108 | // number of declared errors might have increased now | ||
| 7109 | update_errors_helper(ira->codegen, &errors, &errors_count); | ||
| 7110 | |||
| 7111 | // if err_set_type is a superset of cur_type, keep err_set_type. | ||
| 7112 | // if cur_type is a superset of err_set_type, switch err_set_type to cur_type | ||
| 7113 | bool prev_is_superset = true; | ||
| 7114 | for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) { | ||
| 7115 | ErrorTableEntry *contained_error_entry = cur_type->data.error_set.errors[i]; | ||
| 7116 | ErrorTableEntry *error_entry = errors[contained_error_entry->value]; | ||
| 7117 | if (error_entry == nullptr) { | ||
| 7118 | prev_is_superset = false; | ||
| 7119 | break; | ||
| 7120 | } | ||
| 7121 | } | ||
| 7122 | if (prev_is_superset) { | ||
| 7123 | continue; | ||
| 7124 | } | ||
| 7125 | |||
| 7126 | // unset everything in errors | ||
| 7127 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | ||
| 7128 | ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; | ||
| 7129 | errors[error_entry->value] = nullptr; | ||
| 7130 | } | ||
| 7131 | for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) { | ||
| 7132 | assert(errors[i] == nullptr); | ||
| 7133 | } | ||
| 7134 | for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) { | ||
| 7135 | ErrorTableEntry *error_entry = cur_type->data.error_set.errors[i]; | ||
| 7136 | assert(errors[error_entry->value] == nullptr); | ||
| 7137 | errors[error_entry->value] = error_entry; | ||
| 7138 | } | ||
| 7139 | bool cur_is_superset = true; | ||
| 7140 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | ||
| 7141 | ErrorTableEntry *contained_error_entry = err_set_type->data.error_set.errors[i]; | ||
| 7142 | ErrorTableEntry *error_entry = errors[contained_error_entry->value]; | ||
| 7143 | if (error_entry == nullptr) { | ||
| 7144 | cur_is_superset = false; | ||
| 7145 | break; | ||
| 7146 | } | ||
| 7147 | } | ||
| 7148 | if (cur_is_superset) { | ||
| 7149 | err_set_type = cur_type; | ||
| 7150 | prev_inst = cur_inst; | ||
| 7151 | assert(errors != nullptr); | ||
| 7152 | continue; | ||
| 7153 | } | ||
| 7154 | |||
| 7155 | // neither of them are supersets. so we invent a new error set type that is a union of both of them | ||
| 7156 | err_set_type = get_error_set_union(ira->codegen, errors, cur_type, err_set_type); | ||
| 7157 | assert(errors != nullptr); | ||
| 7158 | continue; | ||
| 7159 | } else if (cur_type->id == TypeTableEntryIdErrorUnion) { | ||
| 7160 | if (type_is_global_error_set(err_set_type)) { | ||
| 7161 | prev_inst = cur_inst; | ||
| 7162 | continue; | ||
| 7163 | } | ||
| 7164 | TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type; | ||
| 7165 | if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) { | ||
| 7166 | return ira->codegen->builtin_types.entry_invalid; | ||
| 7167 | } | ||
| 7168 | if (type_is_global_error_set(cur_err_set_type)) { | ||
| 7169 | err_set_type = ira->codegen->builtin_types.entry_global_error_set; | ||
| 7170 | prev_inst = cur_inst; | ||
| 7171 | continue; | ||
| 7172 | } | ||
| 7173 | |||
| 7174 | update_errors_helper(ira->codegen, &errors, &errors_count); | ||
| 7175 | |||
| 7176 | // test if err_set_type is a subset of cur_type's error set | ||
| 7177 | // unset everything in errors | ||
| 7178 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | ||
| 7179 | ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; | ||
| 7180 | errors[error_entry->value] = nullptr; | ||
| 7181 | } | ||
| 7182 | for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) { | ||
| 7183 | assert(errors[i] == nullptr); | ||
| 7184 | } | ||
| 7185 | for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) { | ||
| 7186 | ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i]; | ||
| 7187 | assert(errors[error_entry->value] == nullptr); | ||
| 7188 | errors[error_entry->value] = error_entry; | ||
| 7189 | } | ||
| 7190 | bool cur_is_superset = true; | ||
| 7191 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | ||
| 7192 | ErrorTableEntry *contained_error_entry = err_set_type->data.error_set.errors[i]; | ||
| 7193 | ErrorTableEntry *error_entry = errors[contained_error_entry->value]; | ||
| 7194 | if (error_entry == nullptr) { | ||
| 7195 | cur_is_superset = false; | ||
| 7196 | break; | ||
| 7197 | } | ||
| 7198 | } | ||
| 7199 | if (cur_is_superset) { | ||
| 7200 | err_set_type = cur_err_set_type; | ||
| 7201 | prev_inst = cur_inst; | ||
| 7202 | assert(errors != nullptr); | ||
| 7203 | continue; | ||
| 7204 | } | ||
| 7205 | |||
| 7206 | // not a subset. invent new error set type, union of both of them | ||
| 7207 | err_set_type = get_error_set_union(ira->codegen, errors, cur_err_set_type, err_set_type); | ||
| 7208 | prev_inst = cur_inst; | ||
| 7209 | assert(errors != nullptr); | ||
| 7210 | continue; | ||
| 7211 | } else { | ||
| 7212 | prev_inst = cur_inst; | ||
| 7213 | continue; | ||
| 7214 | } | ||
| 7215 | } | ||
| 7216 | |||
| 7217 | if (cur_type->id == TypeTableEntryIdErrorSet) { | ||
| 6552 | if (prev_type->id == TypeTableEntryIdArray) { | 7218 | if (prev_type->id == TypeTableEntryIdArray) { |
| 6553 | convert_to_const_slice = true; | 7219 | convert_to_const_slice = true; |
| 6554 | } | 7220 | } |
| 6555 | any_are_pure_error = true; | 7221 | if (type_is_global_error_set(cur_type)) { |
| 7222 | err_set_type = ira->codegen->builtin_types.entry_global_error_set; | ||
| 7223 | continue; | ||
| 7224 | } | ||
| 7225 | if (err_set_type != nullptr && type_is_global_error_set(err_set_type)) { | ||
| 7226 | continue; | ||
| 7227 | } | ||
| 7228 | if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) { | ||
| 7229 | return ira->codegen->builtin_types.entry_invalid; | ||
| 7230 | } | ||
| 7231 | |||
| 7232 | update_errors_helper(ira->codegen, &errors, &errors_count); | ||
| 7233 | |||
| 7234 | if (err_set_type == nullptr) { | ||
| 7235 | if (prev_type->id == TypeTableEntryIdErrorUnion) { | ||
| 7236 | err_set_type = prev_type->data.error_union.err_set_type; | ||
| 7237 | } else { | ||
| 7238 | err_set_type = cur_type; | ||
| 7239 | } | ||
| 7240 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | ||
| 7241 | ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; | ||
| 7242 | assert(errors[error_entry->value] == nullptr); | ||
| 7243 | errors[error_entry->value] = error_entry; | ||
| 7244 | } | ||
| 7245 | if (err_set_type == cur_type) { | ||
| 7246 | continue; | ||
| 7247 | } | ||
| 7248 | } | ||
| 7249 | // check if the cur type error set is a subset | ||
| 7250 | bool prev_is_superset = true; | ||
| 7251 | for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) { | ||
| 7252 | ErrorTableEntry *contained_error_entry = cur_type->data.error_set.errors[i]; | ||
| 7253 | ErrorTableEntry *error_entry = errors[contained_error_entry->value]; | ||
| 7254 | if (error_entry == nullptr) { | ||
| 7255 | prev_is_superset = false; | ||
| 7256 | break; | ||
| 7257 | } | ||
| 7258 | } | ||
| 7259 | if (prev_is_superset) { | ||
| 7260 | continue; | ||
| 7261 | } | ||
| 7262 | // not a subset. invent new error set type, union of both of them | ||
| 7263 | err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_type); | ||
| 7264 | assert(errors != nullptr); | ||
| 6556 | continue; | 7265 | continue; |
| 6557 | } | 7266 | } |
| 6558 | 7267 | ||
| 6559 | if (cur_type->id == TypeTableEntryIdNullLit) { | 7268 | if (prev_type->id == TypeTableEntryIdErrorUnion && cur_type->id == TypeTableEntryIdErrorUnion) { |
| 6560 | any_are_null = true; | 7269 | TypeTableEntry *prev_payload_type = prev_type->data.error_union.payload_type; |
| 6561 | continue; | 7270 | TypeTableEntry *cur_payload_type = cur_type->data.error_union.payload_type; |
| 7271 | |||
| 7272 | bool const_cast_prev = types_match_const_cast_only(ira, prev_payload_type, cur_payload_type, | ||
| 7273 | source_node).id == ConstCastResultIdOk; | ||
| 7274 | bool const_cast_cur = types_match_const_cast_only(ira, cur_payload_type, prev_payload_type, | ||
| 7275 | source_node).id == ConstCastResultIdOk; | ||
| 7276 | |||
| 7277 | if (const_cast_prev || const_cast_cur) { | ||
| 7278 | if (const_cast_cur) { | ||
| 7279 | prev_inst = cur_inst; | ||
| 7280 | } | ||
| 7281 | |||
| 7282 | TypeTableEntry *prev_err_set_type = prev_type->data.error_union.err_set_type; | ||
| 7283 | TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type; | ||
| 7284 | |||
| 7285 | if (!resolve_inferred_error_set(ira, prev_err_set_type, cur_inst->source_node)) { | ||
| 7286 | return ira->codegen->builtin_types.entry_invalid; | ||
| 7287 | } | ||
| 7288 | |||
| 7289 | if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) { | ||
| 7290 | return ira->codegen->builtin_types.entry_invalid; | ||
| 7291 | } | ||
| 7292 | |||
| 7293 | if (type_is_global_error_set(prev_err_set_type) || type_is_global_error_set(cur_err_set_type)) { | ||
| 7294 | err_set_type = ira->codegen->builtin_types.entry_global_error_set; | ||
| 7295 | continue; | ||
| 7296 | } | ||
| 7297 | |||
| 7298 | update_errors_helper(ira->codegen, &errors, &errors_count); | ||
| 7299 | |||
| 7300 | if (err_set_type == nullptr) { | ||
| 7301 | err_set_type = prev_err_set_type; | ||
| 7302 | for (uint32_t i = 0; i < prev_err_set_type->data.error_set.err_count; i += 1) { | ||
| 7303 | ErrorTableEntry *error_entry = prev_err_set_type->data.error_set.errors[i]; | ||
| 7304 | assert(errors[error_entry->value] == nullptr); | ||
| 7305 | errors[error_entry->value] = error_entry; | ||
| 7306 | } | ||
| 7307 | } | ||
| 7308 | bool prev_is_superset = true; | ||
| 7309 | for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) { | ||
| 7310 | ErrorTableEntry *contained_error_entry = cur_err_set_type->data.error_set.errors[i]; | ||
| 7311 | ErrorTableEntry *error_entry = errors[contained_error_entry->value]; | ||
| 7312 | if (error_entry == nullptr) { | ||
| 7313 | prev_is_superset = false; | ||
| 7314 | break; | ||
| 7315 | } | ||
| 7316 | } | ||
| 7317 | if (prev_is_superset) { | ||
| 7318 | continue; | ||
| 7319 | } | ||
| 7320 | // unset all the errors | ||
| 7321 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | ||
| 7322 | ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; | ||
| 7323 | errors[error_entry->value] = nullptr; | ||
| 7324 | } | ||
| 7325 | for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) { | ||
| 7326 | assert(errors[i] == nullptr); | ||
| 7327 | } | ||
| 7328 | for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) { | ||
| 7329 | ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i]; | ||
| 7330 | assert(errors[error_entry->value] == nullptr); | ||
| 7331 | errors[error_entry->value] = error_entry; | ||
| 7332 | } | ||
| 7333 | bool cur_is_superset = true; | ||
| 7334 | for (uint32_t i = 0; i < prev_err_set_type->data.error_set.err_count; i += 1) { | ||
| 7335 | ErrorTableEntry *contained_error_entry = prev_err_set_type->data.error_set.errors[i]; | ||
| 7336 | ErrorTableEntry *error_entry = errors[contained_error_entry->value]; | ||
| 7337 | if (error_entry == nullptr) { | ||
| 7338 | cur_is_superset = false; | ||
| 7339 | break; | ||
| 7340 | } | ||
| 7341 | } | ||
| 7342 | if (cur_is_superset) { | ||
| 7343 | err_set_type = cur_err_set_type; | ||
| 7344 | continue; | ||
| 7345 | } | ||
| 7346 | |||
| 7347 | err_set_type = get_error_set_union(ira->codegen, errors, cur_err_set_type, prev_err_set_type); | ||
| 7348 | continue; | ||
| 7349 | } | ||
| 6562 | } | 7350 | } |
| 6563 | 7351 | ||
| 6564 | if (types_match_const_cast_only(prev_type, cur_type)) { | 7352 | if (types_match_const_cast_only(ira, prev_type, cur_type, source_node).id == ConstCastResultIdOk) { |
| 6565 | continue; | 7353 | continue; |
| 6566 | } | 7354 | } |
| 6567 | 7355 | ||
| 6568 | if (types_match_const_cast_only(cur_type, prev_type)) { | 7356 | if (types_match_const_cast_only(ira, cur_type, prev_type, source_node).id == ConstCastResultIdOk) { |
| 6569 | prev_inst = cur_inst; | 7357 | prev_inst = cur_inst; |
| 6570 | continue; | 7358 | continue; |
| 6571 | } | 7359 | } |
| ... | @@ -6588,26 +7376,41 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -6588,26 +7376,41 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 6588 | } | 7376 | } |
| 6589 | 7377 | ||
| 6590 | if (prev_type->id == TypeTableEntryIdErrorUnion && | 7378 | if (prev_type->id == TypeTableEntryIdErrorUnion && |
| 6591 | types_match_const_cast_only(prev_type->data.error.child_type, cur_type)) | 7379 | types_match_const_cast_only(ira, prev_type->data.error_union.payload_type, cur_type, source_node).id == ConstCastResultIdOk) |
| 6592 | { | 7380 | { |
| 6593 | continue; | 7381 | continue; |
| 6594 | } | 7382 | } |
| 6595 | 7383 | ||
| 6596 | if (cur_type->id == TypeTableEntryIdErrorUnion && | 7384 | if (cur_type->id == TypeTableEntryIdErrorUnion && |
| 6597 | types_match_const_cast_only(cur_type->data.error.child_type, prev_type)) | 7385 | types_match_const_cast_only(ira, cur_type->data.error_union.payload_type, prev_type, source_node).id == ConstCastResultIdOk) |
| 6598 | { | 7386 | { |
| 7387 | if (err_set_type != nullptr) { | ||
| 7388 | TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type; | ||
| 7389 | if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) { | ||
| 7390 | return ira->codegen->builtin_types.entry_invalid; | ||
| 7391 | } | ||
| 7392 | if (type_is_global_error_set(cur_err_set_type) || type_is_global_error_set(err_set_type)) { | ||
| 7393 | err_set_type = ira->codegen->builtin_types.entry_global_error_set; | ||
| 7394 | prev_inst = cur_inst; | ||
| 7395 | continue; | ||
| 7396 | } | ||
| 7397 | |||
| 7398 | update_errors_helper(ira->codegen, &errors, &errors_count); | ||
| 7399 | |||
| 7400 | err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_err_set_type); | ||
| 7401 | } | ||
| 6599 | prev_inst = cur_inst; | 7402 | prev_inst = cur_inst; |
| 6600 | continue; | 7403 | continue; |
| 6601 | } | 7404 | } |
| 6602 | 7405 | ||
| 6603 | if (prev_type->id == TypeTableEntryIdMaybe && | 7406 | if (prev_type->id == TypeTableEntryIdMaybe && |
| 6604 | types_match_const_cast_only(prev_type->data.maybe.child_type, cur_type)) | 7407 | types_match_const_cast_only(ira, prev_type->data.maybe.child_type, cur_type, source_node).id == ConstCastResultIdOk) |
| 6605 | { | 7408 | { |
| 6606 | continue; | 7409 | continue; |
| 6607 | } | 7410 | } |
| 6608 | 7411 | ||
| 6609 | if (cur_type->id == TypeTableEntryIdMaybe && | 7412 | if (cur_type->id == TypeTableEntryIdMaybe && |
| 6610 | types_match_const_cast_only(cur_type->data.maybe.child_type, prev_type)) | 7413 | types_match_const_cast_only(ira, cur_type->data.maybe.child_type, prev_type, source_node).id == ConstCastResultIdOk) |
| 6611 | { | 7414 | { |
| 6612 | prev_inst = cur_inst; | 7415 | prev_inst = cur_inst; |
| 6613 | continue; | 7416 | continue; |
| ... | @@ -6645,7 +7448,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -6645,7 +7448,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 6645 | 7448 | ||
| 6646 | if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray && | 7449 | if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray && |
| 6647 | cur_type->data.array.len != prev_type->data.array.len && | 7450 | cur_type->data.array.len != prev_type->data.array.len && |
| 6648 | types_match_const_cast_only(cur_type->data.array.child_type, prev_type->data.array.child_type)) | 7451 | types_match_const_cast_only(ira, cur_type->data.array.child_type, prev_type->data.array.child_type, source_node).id == ConstCastResultIdOk) |
| 6649 | { | 7452 | { |
| 6650 | convert_to_const_slice = true; | 7453 | convert_to_const_slice = true; |
| 6651 | prev_inst = cur_inst; | 7454 | prev_inst = cur_inst; |
| ... | @@ -6654,7 +7457,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -6654,7 +7457,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 6654 | 7457 | ||
| 6655 | if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray && | 7458 | if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray && |
| 6656 | cur_type->data.array.len != prev_type->data.array.len && | 7459 | cur_type->data.array.len != prev_type->data.array.len && |
| 6657 | types_match_const_cast_only(prev_type->data.array.child_type, cur_type->data.array.child_type)) | 7460 | types_match_const_cast_only(ira, prev_type->data.array.child_type, cur_type->data.array.child_type, source_node).id == ConstCastResultIdOk) |
| 6658 | { | 7461 | { |
| 6659 | convert_to_const_slice = true; | 7462 | convert_to_const_slice = true; |
| 6660 | continue; | 7463 | continue; |
| ... | @@ -6663,8 +7466,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -6663,8 +7466,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 6663 | if (cur_type->id == TypeTableEntryIdArray && is_slice(prev_type) && | 7466 | if (cur_type->id == TypeTableEntryIdArray && is_slice(prev_type) && |
| 6664 | (prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const || | 7467 | (prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const || |
| 6665 | cur_type->data.array.len == 0) && | 7468 | cur_type->data.array.len == 0) && |
| 6666 | types_match_const_cast_only(prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type, | 7469 | types_match_const_cast_only(ira, prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type, |
| 6667 | cur_type->data.array.child_type)) | 7470 | cur_type->data.array.child_type, source_node).id == ConstCastResultIdOk) |
| 6668 | { | 7471 | { |
| 6669 | convert_to_const_slice = false; | 7472 | convert_to_const_slice = false; |
| 6670 | continue; | 7473 | continue; |
| ... | @@ -6673,8 +7476,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -6673,8 +7476,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 6673 | if (prev_type->id == TypeTableEntryIdArray && is_slice(cur_type) && | 7476 | if (prev_type->id == TypeTableEntryIdArray && is_slice(cur_type) && |
| 6674 | (cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const || | 7477 | (cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const || |
| 6675 | prev_type->data.array.len == 0) && | 7478 | prev_type->data.array.len == 0) && |
| 6676 | types_match_const_cast_only(cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type, | 7479 | types_match_const_cast_only(ira, cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type, |
| 6677 | prev_type->data.array.child_type)) | 7480 | prev_type->data.array.child_type, source_node).id == ConstCastResultIdOk) |
| 6678 | { | 7481 | { |
| 6679 | prev_inst = cur_inst; | 7482 | prev_inst = cur_inst; |
| 6680 | convert_to_const_slice = false; | 7483 | convert_to_const_slice = false; |
| ... | @@ -6714,30 +7517,37 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -6714,30 +7517,37 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 6714 | 7517 | ||
| 6715 | return ira->codegen->builtin_types.entry_invalid; | 7518 | return ira->codegen->builtin_types.entry_invalid; |
| 6716 | } | 7519 | } |
| 7520 | |||
| 7521 | free(errors); | ||
| 7522 | |||
| 6717 | if (convert_to_const_slice) { | 7523 | if (convert_to_const_slice) { |
| 6718 | assert(prev_inst->value.type->id == TypeTableEntryIdArray); | 7524 | assert(prev_inst->value.type->id == TypeTableEntryIdArray); |
| 6719 | TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, prev_inst->value.type->data.array.child_type, true); | 7525 | TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, prev_inst->value.type->data.array.child_type, true); |
| 6720 | TypeTableEntry *slice_type = get_slice_type(ira->codegen, ptr_type); | 7526 | TypeTableEntry *slice_type = get_slice_type(ira->codegen, ptr_type); |
| 6721 | if (any_are_pure_error) { | 7527 | if (err_set_type != nullptr) { |
| 6722 | return get_error_type(ira->codegen, slice_type); | 7528 | return get_error_union_type(ira->codegen, err_set_type, slice_type); |
| 6723 | } else { | 7529 | } else { |
| 6724 | return slice_type; | 7530 | return slice_type; |
| 6725 | } | 7531 | } |
| 6726 | } else if (any_are_pure_error && prev_inst->value.type->id != TypeTableEntryIdPureError) { | 7532 | } else if (err_set_type != nullptr) { |
| 6727 | if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt || | 7533 | if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) { |
| 6728 | prev_inst->value.type->id == TypeTableEntryIdNumLitFloat) | 7534 | return err_set_type; |
| 6729 | { | ||
| 6730 | ir_add_error_node(ira, source_node, | ||
| 6731 | buf_sprintf("unable to make error union out of number literal")); | ||
| 6732 | return ira->codegen->builtin_types.entry_invalid; | ||
| 6733 | } else if (prev_inst->value.type->id == TypeTableEntryIdNullLit) { | ||
| 6734 | ir_add_error_node(ira, source_node, | ||
| 6735 | buf_sprintf("unable to make error union out of null literal")); | ||
| 6736 | return ira->codegen->builtin_types.entry_invalid; | ||
| 6737 | } else if (prev_inst->value.type->id == TypeTableEntryIdErrorUnion) { | ||
| 6738 | return prev_inst->value.type; | ||
| 6739 | } else { | 7535 | } else { |
| 6740 | return get_error_type(ira->codegen, prev_inst->value.type); | 7536 | if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt || |
| 7537 | prev_inst->value.type->id == TypeTableEntryIdNumLitFloat) | ||
| 7538 | { | ||
| 7539 | ir_add_error_node(ira, source_node, | ||
| 7540 | buf_sprintf("unable to make error union out of number literal")); | ||
| 7541 | return ira->codegen->builtin_types.entry_invalid; | ||
| 7542 | } else if (prev_inst->value.type->id == TypeTableEntryIdNullLit) { | ||
| 7543 | ir_add_error_node(ira, source_node, | ||
| 7544 | buf_sprintf("unable to make error union out of null literal")); | ||
| 7545 | return ira->codegen->builtin_types.entry_invalid; | ||
| 7546 | } else if (prev_inst->value.type->id == TypeTableEntryIdErrorUnion) { | ||
| 7547 | return get_error_union_type(ira->codegen, err_set_type, prev_inst->value.type->data.error_union.payload_type); | ||
| 7548 | } else { | ||
| 7549 | return get_error_union_type(ira->codegen, err_set_type, prev_inst->value.type); | ||
| 7550 | } | ||
| 6741 | } | 7551 | } |
| 6742 | } else if (any_are_null && prev_inst->value.type->id != TypeTableEntryIdNullLit) { | 7552 | } else if (any_are_null && prev_inst->value.type->id != TypeTableEntryIdNullLit) { |
| 6743 | if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt || | 7553 | if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt || |
| ... | @@ -6783,6 +7593,8 @@ static void eval_const_expr_implicit_cast(CastOp cast_op, | ... | @@ -6783,6 +7593,8 @@ static void eval_const_expr_implicit_cast(CastOp cast_op, |
| 6783 | switch (cast_op) { | 7593 | switch (cast_op) { |
| 6784 | case CastOpNoCast: | 7594 | case CastOpNoCast: |
| 6785 | zig_unreachable(); | 7595 | zig_unreachable(); |
| 7596 | case CastOpErrSet: | ||
| 7597 | zig_panic("TODO"); | ||
| 6786 | case CastOpNoop: | 7598 | case CastOpNoop: |
| 6787 | { | 7599 | { |
| 6788 | copy_const_val(const_val, other_val, other_val->special == ConstValSpecialStatic); | 7600 | copy_const_val(const_val, other_val, other_val->special == ConstValSpecialStatic); |
| ... | @@ -7213,7 +8025,7 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction | ... | @@ -7213,7 +8025,7 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction |
| 7213 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); | 8025 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); |
| 7214 | 8026 | ||
| 7215 | if (instr_is_comptime(value)) { | 8027 | if (instr_is_comptime(value)) { |
| 7216 | TypeTableEntry *payload_type = wanted_type->data.error.child_type; | 8028 | TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type; |
| 7217 | IrInstruction *casted_payload = ir_implicit_cast(ira, value, payload_type); | 8029 | IrInstruction *casted_payload = ir_implicit_cast(ira, value, payload_type); |
| 7218 | if (type_is_invalid(casted_payload->value.type)) | 8030 | if (type_is_invalid(casted_payload->value.type)) |
| 7219 | return ira->codegen->invalid_instruction; | 8031 | return ira->codegen->invalid_instruction; |
| ... | @@ -7238,19 +8050,64 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction | ... | @@ -7238,19 +8050,64 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction |
| 7238 | return result; | 8050 | return result; |
| 7239 | } | 8051 | } |
| 7240 | 8052 | ||
| 7241 | static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) { | 8053 | static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, |
| 7242 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); | 8054 | TypeTableEntry *wanted_type) |
| 8055 | { | ||
| 8056 | assert(value->value.type->id == TypeTableEntryIdErrorSet); | ||
| 8057 | assert(wanted_type->id == TypeTableEntryIdErrorSet); | ||
| 7243 | 8058 | ||
| 7244 | if (instr_is_comptime(value)) { | 8059 | if (instr_is_comptime(value)) { |
| 7245 | ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); | 8060 | ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); |
| 7246 | if (!val) | 8061 | if (!val) |
| 7247 | return ira->codegen->invalid_instruction; | 8062 | return ira->codegen->invalid_instruction; |
| 7248 | 8063 | ||
| 8064 | if (!resolve_inferred_error_set(ira, wanted_type, source_instr->source_node)) { | ||
| 8065 | return ira->codegen->invalid_instruction; | ||
| 8066 | } | ||
| 8067 | if (!type_is_global_error_set(wanted_type)) { | ||
| 8068 | bool subset = false; | ||
| 8069 | for (uint32_t i = 0, count = wanted_type->data.error_set.err_count; i < count; i += 1) { | ||
| 8070 | if (wanted_type->data.error_set.errors[i]->value == val->data.x_err_set->value) { | ||
| 8071 | subset = true; | ||
| 8072 | break; | ||
| 8073 | } | ||
| 8074 | } | ||
| 8075 | if (!subset) { | ||
| 8076 | ir_add_error(ira, source_instr, | ||
| 8077 | buf_sprintf("error.%s not a member of error set '%s'", | ||
| 8078 | buf_ptr(&val->data.x_err_set->name), buf_ptr(&wanted_type->name))); | ||
| 8079 | return ira->codegen->invalid_instruction; | ||
| 8080 | } | ||
| 8081 | } | ||
| 8082 | |||
| 7249 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, | 8083 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, |
| 7250 | source_instr->scope, source_instr->source_node); | 8084 | source_instr->scope, source_instr->source_node); |
| 7251 | const_instruction->base.value.type = wanted_type; | 8085 | const_instruction->base.value.type = wanted_type; |
| 7252 | const_instruction->base.value.special = ConstValSpecialStatic; | 8086 | const_instruction->base.value.special = ConstValSpecialStatic; |
| 7253 | const_instruction->base.value.data.x_err_union.err = val->data.x_pure_err; | 8087 | const_instruction->base.value.data.x_err_set = val->data.x_err_set; |
| 8088 | return &const_instruction->base; | ||
| 8089 | } | ||
| 8090 | |||
| 8091 | IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, CastOpErrSet); | ||
| 8092 | result->value.type = wanted_type; | ||
| 8093 | return result; | ||
| 8094 | } | ||
| 8095 | |||
| 8096 | static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) { | ||
| 8097 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); | ||
| 8098 | |||
| 8099 | IrInstruction *casted_value = ir_implicit_cast(ira, value, wanted_type->data.error_union.err_set_type); | ||
| 8100 | |||
| 8101 | if (instr_is_comptime(casted_value)) { | ||
| 8102 | ConstExprValue *val = ir_resolve_const(ira, casted_value, UndefBad); | ||
| 8103 | if (!val) | ||
| 8104 | return ira->codegen->invalid_instruction; | ||
| 8105 | |||
| 8106 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, | ||
| 8107 | source_instr->scope, source_instr->source_node); | ||
| 8108 | const_instruction->base.value.type = wanted_type; | ||
| 8109 | const_instruction->base.value.special = ConstValSpecialStatic; | ||
| 8110 | const_instruction->base.value.data.x_err_union.err = val->data.x_err_set; | ||
| 7254 | const_instruction->base.value.data.x_err_union.payload = nullptr; | 8111 | const_instruction->base.value.data.x_err_union.payload = nullptr; |
| 7255 | return &const_instruction->base; | 8112 | return &const_instruction->base; |
| 7256 | } | 8113 | } |
| ... | @@ -7630,36 +8487,68 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction | ... | @@ -7630,36 +8487,68 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction |
| 7630 | return result; | 8487 | return result; |
| 7631 | } | 8488 | } |
| 7632 | 8489 | ||
| 7633 | static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target) { | 8490 | static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target, |
| 8491 | TypeTableEntry *wanted_type) | ||
| 8492 | { | ||
| 7634 | assert(target->value.type->id == TypeTableEntryIdInt); | 8493 | assert(target->value.type->id == TypeTableEntryIdInt); |
| 7635 | assert(!target->value.type->data.integral.is_signed); | 8494 | assert(!target->value.type->data.integral.is_signed); |
| 8495 | assert(wanted_type->id == TypeTableEntryIdErrorSet); | ||
| 7636 | 8496 | ||
| 7637 | if (instr_is_comptime(target)) { | 8497 | if (instr_is_comptime(target)) { |
| 7638 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); | 8498 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); |
| 7639 | if (!val) | 8499 | if (!val) |
| 7640 | return ira->codegen->invalid_instruction; | 8500 | return ira->codegen->invalid_instruction; |
| 7641 | 8501 | ||
| 7642 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | 8502 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, |
| 7643 | source_instr->source_node, ira->codegen->builtin_types.entry_pure_error); | 8503 | source_instr->source_node, wanted_type); |
| 8504 | |||
| 8505 | if (!resolve_inferred_error_set(ira, wanted_type, source_instr->source_node)) { | ||
| 8506 | return ira->codegen->invalid_instruction; | ||
| 8507 | } | ||
| 8508 | |||
| 8509 | if (type_is_global_error_set(wanted_type)) { | ||
| 8510 | BigInt err_count; | ||
| 8511 | bigint_init_unsigned(&err_count, ira->codegen->errors_by_index.length); | ||
| 8512 | |||
| 8513 | if (bigint_cmp_zero(&val->data.x_bigint) == CmpEQ || bigint_cmp(&val->data.x_bigint, &err_count) != CmpLT) { | ||
| 8514 | Buf *val_buf = buf_alloc(); | ||
| 8515 | bigint_append_buf(val_buf, &val->data.x_bigint, 10); | ||
| 8516 | ir_add_error(ira, source_instr, | ||
| 8517 | buf_sprintf("integer value %s represents no error", buf_ptr(val_buf))); | ||
| 8518 | return ira->codegen->invalid_instruction; | ||
| 8519 | } | ||
| 8520 | |||
| 8521 | size_t index = bigint_as_unsigned(&val->data.x_bigint); | ||
| 8522 | result->value.data.x_err_set = ira->codegen->errors_by_index.at(index); | ||
| 8523 | return result; | ||
| 8524 | } else { | ||
| 8525 | ErrorTableEntry *err = nullptr; | ||
| 8526 | BigInt err_int; | ||
| 8527 | |||
| 8528 | for (uint32_t i = 0, count = wanted_type->data.error_set.err_count; i < count; i += 1) { | ||
| 8529 | ErrorTableEntry *this_err = wanted_type->data.error_set.errors[i]; | ||
| 8530 | bigint_init_unsigned(&err_int, this_err->value); | ||
| 8531 | if (bigint_cmp(&val->data.x_bigint, &err_int) == CmpEQ) { | ||
| 8532 | err = this_err; | ||
| 8533 | break; | ||
| 8534 | } | ||
| 8535 | } | ||
| 7644 | 8536 | ||
| 7645 | BigInt err_count; | 8537 | if (err == nullptr) { |
| 7646 | bigint_init_unsigned(&err_count, ira->codegen->error_decls.length); | 8538 | Buf *val_buf = buf_alloc(); |
| 7647 | if (bigint_cmp_zero(&val->data.x_bigint) == CmpEQ || bigint_cmp(&val->data.x_bigint, &err_count) != CmpLT) { | 8539 | bigint_append_buf(val_buf, &val->data.x_bigint, 10); |
| 7648 | Buf *val_buf = buf_alloc(); | 8540 | ir_add_error(ira, source_instr, |
| 7649 | bigint_append_buf(val_buf, &val->data.x_bigint, 10); | 8541 | buf_sprintf("integer value %s represents no error in '%s'", buf_ptr(val_buf), buf_ptr(&wanted_type->name))); |
| 7650 | ir_add_error(ira, source_instr, | 8542 | return ira->codegen->invalid_instruction; |
| 7651 | buf_sprintf("integer value %s represents no error", buf_ptr(val_buf))); | 8543 | } |
| 7652 | return ira->codegen->invalid_instruction; | ||
| 7653 | } | ||
| 7654 | 8544 | ||
| 7655 | size_t index = bigint_as_unsigned(&val->data.x_bigint); | 8545 | result->value.data.x_err_set = err; |
| 7656 | AstNode *error_decl_node = ira->codegen->error_decls.at(index); | 8546 | return result; |
| 7657 | result->value.data.x_pure_err = error_decl_node->data.error_value_decl.err; | 8547 | } |
| 7658 | return result; | ||
| 7659 | } | 8548 | } |
| 7660 | 8549 | ||
| 7661 | IrInstruction *result = ir_build_int_to_err(&ira->new_irb, source_instr->scope, source_instr->source_node, target); | 8550 | IrInstruction *result = ir_build_int_to_err(&ira->new_irb, source_instr->scope, source_instr->source_node, target); |
| 7662 | result->value.type = ira->codegen->builtin_types.entry_pure_error; | 8551 | result->value.type = wanted_type; |
| 7663 | return result; | 8552 | return result; |
| 7664 | } | 8553 | } |
| 7665 | 8554 | ||
| ... | @@ -7681,8 +8570,8 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc | ... | @@ -7681,8 +8570,8 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc |
| 7681 | ErrorTableEntry *err; | 8570 | ErrorTableEntry *err; |
| 7682 | if (err_type->id == TypeTableEntryIdErrorUnion) { | 8571 | if (err_type->id == TypeTableEntryIdErrorUnion) { |
| 7683 | err = val->data.x_err_union.err; | 8572 | err = val->data.x_err_union.err; |
| 7684 | } else if (err_type->id == TypeTableEntryIdPureError) { | 8573 | } else if (err_type->id == TypeTableEntryIdErrorSet) { |
| 7685 | err = val->data.x_pure_err; | 8574 | err = val->data.x_err_set; |
| 7686 | } else { | 8575 | } else { |
| 7687 | zig_unreachable(); | 8576 | zig_unreachable(); |
| 7688 | } | 8577 | } |
| ... | @@ -7702,8 +8591,36 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc | ... | @@ -7702,8 +8591,36 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc |
| 7702 | return result; | 8591 | return result; |
| 7703 | } | 8592 | } |
| 7704 | 8593 | ||
| 8594 | TypeTableEntry *err_set_type; | ||
| 8595 | if (err_type->id == TypeTableEntryIdErrorUnion) { | ||
| 8596 | err_set_type = err_type->data.error_union.err_set_type; | ||
| 8597 | } else if (err_type->id == TypeTableEntryIdErrorSet) { | ||
| 8598 | err_set_type = err_type; | ||
| 8599 | } else { | ||
| 8600 | zig_unreachable(); | ||
| 8601 | } | ||
| 8602 | if (!type_is_global_error_set(err_set_type)) { | ||
| 8603 | if (!resolve_inferred_error_set(ira, err_set_type, source_instr->source_node)) { | ||
| 8604 | return ira->codegen->invalid_instruction; | ||
| 8605 | } | ||
| 8606 | if (err_set_type->data.error_set.err_count == 0) { | ||
| 8607 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | ||
| 8608 | source_instr->source_node, wanted_type); | ||
| 8609 | result->value.type = wanted_type; | ||
| 8610 | bigint_init_unsigned(&result->value.data.x_bigint, 0); | ||
| 8611 | return result; | ||
| 8612 | } else if (err_set_type->data.error_set.err_count == 1) { | ||
| 8613 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | ||
| 8614 | source_instr->source_node, wanted_type); | ||
| 8615 | result->value.type = wanted_type; | ||
| 8616 | ErrorTableEntry *err = err_set_type->data.error_set.errors[0]; | ||
| 8617 | bigint_init_unsigned(&result->value.data.x_bigint, err->value); | ||
| 8618 | return result; | ||
| 8619 | } | ||
| 8620 | } | ||
| 8621 | |||
| 7705 | BigInt bn; | 8622 | BigInt bn; |
| 7706 | bigint_init_unsigned(&bn, ira->codegen->error_decls.length); | 8623 | bigint_init_unsigned(&bn, ira->codegen->errors_by_index.length); |
| 7707 | if (!bigint_fits_in_bits(&bn, wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) { | 8624 | if (!bigint_fits_in_bits(&bn, wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) { |
| 7708 | ir_add_error_node(ira, source_instr->source_node, | 8625 | ir_add_error_node(ira, source_instr->source_node, |
| 7709 | buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name))); | 8626 | buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name))); |
| ... | @@ -7719,6 +8636,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -7719,6 +8636,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 7719 | TypeTableEntry *wanted_type, IrInstruction *value) | 8636 | TypeTableEntry *wanted_type, IrInstruction *value) |
| 7720 | { | 8637 | { |
| 7721 | TypeTableEntry *actual_type = value->value.type; | 8638 | TypeTableEntry *actual_type = value->value.type; |
| 8639 | AstNode *source_node = source_instr->source_node; | ||
| 7722 | 8640 | ||
| 7723 | if (type_is_invalid(wanted_type) || type_is_invalid(actual_type)) { | 8641 | if (type_is_invalid(wanted_type) || type_is_invalid(actual_type)) { |
| 7724 | return ira->codegen->invalid_instruction; | 8642 | return ira->codegen->invalid_instruction; |
| ... | @@ -7728,7 +8646,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -7728,7 +8646,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 7728 | return value; | 8646 | return value; |
| 7729 | 8647 | ||
| 7730 | // explicit match or non-const to const | 8648 | // explicit match or non-const to const |
| 7731 | if (types_match_const_cast_only(wanted_type, actual_type)) { | 8649 | if (types_match_const_cast_only(ira, wanted_type, actual_type, source_node).id == ConstCastResultIdOk) { |
| 7732 | return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false); | 8650 | return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false); |
| 7733 | } | 8651 | } |
| 7734 | 8652 | ||
| ... | @@ -7748,6 +8666,13 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -7748,6 +8666,13 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 7748 | return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); | 8666 | return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); |
| 7749 | } | 8667 | } |
| 7750 | 8668 | ||
| 8669 | // explicit error set cast | ||
| 8670 | if (wanted_type->id == TypeTableEntryIdErrorSet && | ||
| 8671 | actual_type->id == TypeTableEntryIdErrorSet) | ||
| 8672 | { | ||
| 8673 | return ir_analyze_err_set_cast(ira, source_instr, value, wanted_type); | ||
| 8674 | } | ||
| 8675 | |||
| 7751 | // explicit cast from int to float | 8676 | // explicit cast from int to float |
| 7752 | if (wanted_type->id == TypeTableEntryIdFloat && | 8677 | if (wanted_type->id == TypeTableEntryIdFloat && |
| 7753 | actual_type->id == TypeTableEntryIdInt) | 8678 | actual_type->id == TypeTableEntryIdInt) |
| ... | @@ -7767,7 +8692,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -7767,7 +8692,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 7767 | TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; | 8692 | TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; |
| 7768 | assert(ptr_type->id == TypeTableEntryIdPointer); | 8693 | assert(ptr_type->id == TypeTableEntryIdPointer); |
| 7769 | if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && | 8694 | if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && |
| 7770 | types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) | 8695 | types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk) |
| 7771 | { | 8696 | { |
| 7772 | return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type); | 8697 | return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type); |
| 7773 | } | 8698 | } |
| ... | @@ -7785,7 +8710,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -7785,7 +8710,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 7785 | TypeTableEntry *array_type = actual_type->data.pointer.child_type; | 8710 | TypeTableEntry *array_type = actual_type->data.pointer.child_type; |
| 7786 | 8711 | ||
| 7787 | if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) && | 8712 | if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) && |
| 7788 | types_match_const_cast_only(ptr_type->data.pointer.child_type, array_type->data.array.child_type)) | 8713 | types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type, source_node).id == ConstCastResultIdOk) |
| 7789 | { | 8714 | { |
| 7790 | return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type); | 8715 | return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type); |
| 7791 | } | 8716 | } |
| ... | @@ -7801,7 +8726,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -7801,7 +8726,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 7801 | wanted_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry; | 8726 | wanted_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry; |
| 7802 | assert(ptr_type->id == TypeTableEntryIdPointer); | 8727 | assert(ptr_type->id == TypeTableEntryIdPointer); |
| 7803 | if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && | 8728 | if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && |
| 7804 | types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) | 8729 | types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk) |
| 7805 | { | 8730 | { |
| 7806 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value); | 8731 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value); |
| 7807 | if (type_is_invalid(cast1->value.type)) | 8732 | if (type_is_invalid(cast1->value.type)) |
| ... | @@ -7824,7 +8749,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -7824,7 +8749,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 7824 | wanted_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry; | 8749 | wanted_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry; |
| 7825 | assert(ptr_type->id == TypeTableEntryIdPointer); | 8750 | assert(ptr_type->id == TypeTableEntryIdPointer); |
| 7826 | if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && | 8751 | if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && |
| 7827 | types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) | 8752 | types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk) |
| 7828 | { | 8753 | { |
| 7829 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value); | 8754 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value); |
| 7830 | if (type_is_invalid(cast1->value.type)) | 8755 | if (type_is_invalid(cast1->value.type)) |
| ... | @@ -7886,7 +8811,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -7886,7 +8811,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 7886 | 8811 | ||
| 7887 | // explicit cast from child type of maybe type to maybe type | 8812 | // explicit cast from child type of maybe type to maybe type |
| 7888 | if (wanted_type->id == TypeTableEntryIdMaybe) { | 8813 | if (wanted_type->id == TypeTableEntryIdMaybe) { |
| 7889 | if (types_match_const_cast_only(wanted_type->data.maybe.child_type, actual_type)) { | 8814 | if (types_match_const_cast_only(ira, wanted_type->data.maybe.child_type, actual_type, source_node).id == ConstCastResultIdOk) { |
| 7890 | return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); | 8815 | return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); |
| 7891 | } else if (actual_type->id == TypeTableEntryIdNumLitInt || | 8816 | } else if (actual_type->id == TypeTableEntryIdNumLitInt || |
| 7892 | actual_type->id == TypeTableEntryIdNumLitFloat) | 8817 | actual_type->id == TypeTableEntryIdNumLitFloat) |
| ... | @@ -7908,12 +8833,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -7908,12 +8833,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 7908 | 8833 | ||
| 7909 | // explicit cast from child type of error type to error type | 8834 | // explicit cast from child type of error type to error type |
| 7910 | if (wanted_type->id == TypeTableEntryIdErrorUnion) { | 8835 | if (wanted_type->id == TypeTableEntryIdErrorUnion) { |
| 7911 | if (types_match_const_cast_only(wanted_type->data.error.child_type, actual_type)) { | 8836 | if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type, source_node).id == ConstCastResultIdOk) { |
| 7912 | return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); | 8837 | return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); |
| 7913 | } else if (actual_type->id == TypeTableEntryIdNumLitInt || | 8838 | } else if (actual_type->id == TypeTableEntryIdNumLitInt || |
| 7914 | actual_type->id == TypeTableEntryIdNumLitFloat) | 8839 | actual_type->id == TypeTableEntryIdNumLitFloat) |
| 7915 | { | 8840 | { |
| 7916 | if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error.child_type, true)) { | 8841 | if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error_union.payload_type, true)) { |
| 7917 | return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); | 8842 | return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); |
| 7918 | } else { | 8843 | } else { |
| 7919 | return ira->codegen->invalid_instruction; | 8844 | return ira->codegen->invalid_instruction; |
| ... | @@ -7923,16 +8848,16 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -7923,16 +8848,16 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 7923 | 8848 | ||
| 7924 | // explicit cast from [N]T to %[]const T | 8849 | // explicit cast from [N]T to %[]const T |
| 7925 | if (wanted_type->id == TypeTableEntryIdErrorUnion && | 8850 | if (wanted_type->id == TypeTableEntryIdErrorUnion && |
| 7926 | is_slice(wanted_type->data.error.child_type) && | 8851 | is_slice(wanted_type->data.error_union.payload_type) && |
| 7927 | actual_type->id == TypeTableEntryIdArray) | 8852 | actual_type->id == TypeTableEntryIdArray) |
| 7928 | { | 8853 | { |
| 7929 | TypeTableEntry *ptr_type = | 8854 | TypeTableEntry *ptr_type = |
| 7930 | wanted_type->data.error.child_type->data.structure.fields[slice_ptr_index].type_entry; | 8855 | wanted_type->data.error_union.payload_type->data.structure.fields[slice_ptr_index].type_entry; |
| 7931 | assert(ptr_type->id == TypeTableEntryIdPointer); | 8856 | assert(ptr_type->id == TypeTableEntryIdPointer); |
| 7932 | if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && | 8857 | if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && |
| 7933 | types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) | 8858 | types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk) |
| 7934 | { | 8859 | { |
| 7935 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error.child_type, value); | 8860 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value); |
| 7936 | if (type_is_invalid(cast1->value.type)) | 8861 | if (type_is_invalid(cast1->value.type)) |
| 7937 | return ira->codegen->invalid_instruction; | 8862 | return ira->codegen->invalid_instruction; |
| 7938 | 8863 | ||
| ... | @@ -7944,25 +8869,25 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -7944,25 +8869,25 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 7944 | } | 8869 | } |
| 7945 | } | 8870 | } |
| 7946 | 8871 | ||
| 7947 | // explicit cast from pure error to error union type | 8872 | // explicit cast from error set to error union type |
| 7948 | if (wanted_type->id == TypeTableEntryIdErrorUnion && | 8873 | if (wanted_type->id == TypeTableEntryIdErrorUnion && |
| 7949 | actual_type->id == TypeTableEntryIdPureError) | 8874 | actual_type->id == TypeTableEntryIdErrorSet) |
| 7950 | { | 8875 | { |
| 7951 | return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type); | 8876 | return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type); |
| 7952 | } | 8877 | } |
| 7953 | 8878 | ||
| 7954 | // explicit cast from T to %?T | 8879 | // explicit cast from T to %?T |
| 7955 | if (wanted_type->id == TypeTableEntryIdErrorUnion && | 8880 | if (wanted_type->id == TypeTableEntryIdErrorUnion && |
| 7956 | wanted_type->data.error.child_type->id == TypeTableEntryIdMaybe && | 8881 | wanted_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe && |
| 7957 | actual_type->id != TypeTableEntryIdMaybe) | 8882 | actual_type->id != TypeTableEntryIdMaybe) |
| 7958 | { | 8883 | { |
| 7959 | TypeTableEntry *wanted_child_type = wanted_type->data.error.child_type->data.maybe.child_type; | 8884 | TypeTableEntry *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type; |
| 7960 | if (types_match_const_cast_only(wanted_child_type, actual_type) || | 8885 | if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node).id == ConstCastResultIdOk || |
| 7961 | actual_type->id == TypeTableEntryIdNullLit || | 8886 | actual_type->id == TypeTableEntryIdNullLit || |
| 7962 | actual_type->id == TypeTableEntryIdNumLitInt || | 8887 | actual_type->id == TypeTableEntryIdNumLitInt || |
| 7963 | actual_type->id == TypeTableEntryIdNumLitFloat) | 8888 | actual_type->id == TypeTableEntryIdNumLitFloat) |
| 7964 | { | 8889 | { |
| 7965 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error.child_type, value); | 8890 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value); |
| 7966 | if (type_is_invalid(cast1->value.type)) | 8891 | if (type_is_invalid(cast1->value.type)) |
| 7967 | return ira->codegen->invalid_instruction; | 8892 | return ira->codegen->invalid_instruction; |
| 7968 | 8893 | ||
| ... | @@ -8031,21 +8956,19 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -8031,21 +8956,19 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 8031 | return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type); | 8956 | return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type); |
| 8032 | } | 8957 | } |
| 8033 | 8958 | ||
| 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 |
| 8035 | bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion && | 8960 | bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion && |
| 8036 | !type_has_bits(actual_type->data.error.child_type); | 8961 | !type_has_bits(actual_type->data.error_union.payload_type); |
| 8037 | bool actual_type_is_pure_err = actual_type->id == TypeTableEntryIdPureError; | 8962 | bool actual_type_is_err_set = actual_type->id == TypeTableEntryIdErrorSet; |
| 8038 | if ((actual_type_is_void_err || actual_type_is_pure_err) && | 8963 | if ((actual_type_is_void_err || actual_type_is_err_set) && wanted_type->id == TypeTableEntryIdInt) { |
| 8039 | wanted_type->id == TypeTableEntryIdInt) | ||
| 8040 | { | ||
| 8041 | return ir_analyze_err_to_int(ira, source_instr, value, wanted_type); | 8964 | return ir_analyze_err_to_int(ira, source_instr, value, wanted_type); |
| 8042 | } | 8965 | } |
| 8043 | 8966 | ||
| 8044 | // explicit cast from integer to pure error | 8967 | // explicit cast from integer to error set |
| 8045 | if (wanted_type->id == TypeTableEntryIdPureError && actual_type->id == TypeTableEntryIdInt && | 8968 | if (wanted_type->id == TypeTableEntryIdErrorSet && actual_type->id == TypeTableEntryIdInt && |
| 8046 | !actual_type->data.integral.is_signed) | 8969 | !actual_type->data.integral.is_signed) |
| 8047 | { | 8970 | { |
| 8048 | return ir_analyze_int_to_err(ira, source_instr, value); | 8971 | return ir_analyze_int_to_err(ira, source_instr, value, wanted_type); |
| 8049 | } | 8972 | } |
| 8050 | 8973 | ||
| 8051 | // explicit cast from integer to enum type with no payload | 8974 | // explicit cast from integer to enum type with no payload |
| ... | @@ -8109,7 +9032,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -8109,7 +9032,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 8109 | // explicit cast from something to const pointer of it | 9032 | // explicit cast from something to const pointer of it |
| 8110 | if (!type_requires_comptime(actual_type)) { | 9033 | if (!type_requires_comptime(actual_type)) { |
| 8111 | TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true); | 9034 | TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true); |
| 8112 | if (types_match_const_cast_only(wanted_type, const_ptr_actual)) { | 9035 | if (types_match_const_cast_only(ira, wanted_type, const_ptr_actual, source_node).id == ConstCastResultIdOk) { |
| 8113 | return ir_analyze_cast_ref(ira, source_instr, value, wanted_type); | 9036 | return ir_analyze_cast_ref(ira, source_instr, value, wanted_type); |
| 8114 | } | 9037 | } |
| 8115 | } | 9038 | } |
| ... | @@ -8471,6 +9394,7 @@ static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) { | ... | @@ -8471,6 +9394,7 @@ static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) { |
| 8471 | static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { | 9394 | static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { |
| 8472 | IrInstruction *op1 = bin_op_instruction->op1->other; | 9395 | IrInstruction *op1 = bin_op_instruction->op1->other; |
| 8473 | IrInstruction *op2 = bin_op_instruction->op2->other; | 9396 | IrInstruction *op2 = bin_op_instruction->op2->other; |
| 9397 | AstNode *source_node = bin_op_instruction->base.source_node; | ||
| 8474 | 9398 | ||
| 8475 | IrBinOp op_id = bin_op_instruction->op_id; | 9399 | IrBinOp op_id = bin_op_instruction->op_id; |
| 8476 | bool is_equality_cmp = (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq); | 9400 | bool is_equality_cmp = (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq); |
| ... | @@ -8503,7 +9427,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp | ... | @@ -8503,7 +9427,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 8503 | } | 9427 | } |
| 8504 | 9428 | ||
| 8505 | IrInstruction *is_non_null = ir_build_test_nonnull(&ira->new_irb, bin_op_instruction->base.scope, | 9429 | IrInstruction *is_non_null = ir_build_test_nonnull(&ira->new_irb, bin_op_instruction->base.scope, |
| 8506 | bin_op_instruction->base.source_node, maybe_op); | 9430 | source_node, maybe_op); |
| 8507 | is_non_null->value.type = ira->codegen->builtin_types.entry_bool; | 9431 | is_non_null->value.type = ira->codegen->builtin_types.entry_bool; |
| 8508 | 9432 | ||
| 8509 | if (op_id == IrBinOpCmpEq) { | 9433 | if (op_id == IrBinOpCmpEq) { |
| ... | @@ -8514,8 +9438,88 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp | ... | @@ -8514,8 +9438,88 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 8514 | return ira->codegen->builtin_types.entry_bool; | 9438 | return ira->codegen->builtin_types.entry_bool; |
| 8515 | } | 9439 | } |
| 8516 | 9440 | ||
| 9441 | if (op1->value.type->id == TypeTableEntryIdErrorSet && op2->value.type->id == TypeTableEntryIdErrorSet) { | ||
| 9442 | if (!is_equality_cmp) { | ||
| 9443 | ir_add_error_node(ira, source_node, buf_sprintf("operator not allowed for errors")); | ||
| 9444 | return ira->codegen->builtin_types.entry_invalid; | ||
| 9445 | } | ||
| 9446 | TypeTableEntry *intersect_type = get_error_set_intersection(ira, op1->value.type, op2->value.type, source_node); | ||
| 9447 | if (type_is_invalid(intersect_type)) { | ||
| 9448 | return ira->codegen->builtin_types.entry_invalid; | ||
| 9449 | } | ||
| 9450 | |||
| 9451 | if (!resolve_inferred_error_set(ira, intersect_type, source_node)) { | ||
| 9452 | return ira->codegen->builtin_types.entry_invalid; | ||
| 9453 | } | ||
| 9454 | |||
| 9455 | // exception if one of the operators has the type of the empty error set, we allow the comparison | ||
| 9456 | // (and make it comptime known) | ||
| 9457 | // this is a function which is evaluated at comptime and returns an inferred error set will have an empty | ||
| 9458 | // error set. | ||
| 9459 | if (op1->value.type->data.error_set.err_count == 0 || op2->value.type->data.error_set.err_count == 0) { | ||
| 9460 | bool are_equal = false; | ||
| 9461 | bool answer; | ||
| 9462 | if (op_id == IrBinOpCmpEq) { | ||
| 9463 | answer = are_equal; | ||
| 9464 | } else if (op_id == IrBinOpCmpNotEq) { | ||
| 9465 | answer = !are_equal; | ||
| 9466 | } else { | ||
| 9467 | zig_unreachable(); | ||
| 9468 | } | ||
| 9469 | ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base); | ||
| 9470 | out_val->data.x_bool = answer; | ||
| 9471 | return ira->codegen->builtin_types.entry_bool; | ||
| 9472 | } | ||
| 9473 | |||
| 9474 | if (!type_is_global_error_set(intersect_type)) { | ||
| 9475 | if (intersect_type->data.error_set.err_count == 0) { | ||
| 9476 | ir_add_error_node(ira, source_node, | ||
| 9477 | buf_sprintf("error sets '%s' and '%s' have no common errors", | ||
| 9478 | buf_ptr(&op1->value.type->name), buf_ptr(&op2->value.type->name))); | ||
| 9479 | return ira->codegen->builtin_types.entry_invalid; | ||
| 9480 | } | ||
| 9481 | if (op1->value.type->data.error_set.err_count == 1 && op2->value.type->data.error_set.err_count == 1) { | ||
| 9482 | bool are_equal = true; | ||
| 9483 | bool answer; | ||
| 9484 | if (op_id == IrBinOpCmpEq) { | ||
| 9485 | answer = are_equal; | ||
| 9486 | } else if (op_id == IrBinOpCmpNotEq) { | ||
| 9487 | answer = !are_equal; | ||
| 9488 | } else { | ||
| 9489 | zig_unreachable(); | ||
| 9490 | } | ||
| 9491 | ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base); | ||
| 9492 | out_val->data.x_bool = answer; | ||
| 9493 | return ira->codegen->builtin_types.entry_bool; | ||
| 9494 | } | ||
| 9495 | } | ||
| 9496 | |||
| 9497 | ConstExprValue *op1_val = &op1->value; | ||
| 9498 | ConstExprValue *op2_val = &op2->value; | ||
| 9499 | if (value_is_comptime(op1_val) && value_is_comptime(op2_val)) { | ||
| 9500 | bool answer; | ||
| 9501 | bool are_equal = op1_val->data.x_err_set->value == op2_val->data.x_err_set->value; | ||
| 9502 | if (op_id == IrBinOpCmpEq) { | ||
| 9503 | answer = are_equal; | ||
| 9504 | } else if (op_id == IrBinOpCmpNotEq) { | ||
| 9505 | answer = !are_equal; | ||
| 9506 | } else { | ||
| 9507 | zig_unreachable(); | ||
| 9508 | } | ||
| 9509 | |||
| 9510 | ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base); | ||
| 9511 | out_val->data.x_bool = answer; | ||
| 9512 | return ira->codegen->builtin_types.entry_bool; | ||
| 9513 | } | ||
| 9514 | |||
| 9515 | ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, op_id, | ||
| 9516 | op1, op2, bin_op_instruction->safety_check_on); | ||
| 9517 | |||
| 9518 | return ira->codegen->builtin_types.entry_bool; | ||
| 9519 | } | ||
| 9520 | |||
| 8517 | IrInstruction *instructions[] = {op1, op2}; | 9521 | IrInstruction *instructions[] = {op1, op2}; |
| 8518 | TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, bin_op_instruction->base.source_node, instructions, 2); | 9522 | TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, source_node, instructions, 2); |
| 8519 | if (type_is_invalid(resolved_type)) | 9523 | if (type_is_invalid(resolved_type)) |
| 8520 | return resolved_type; | 9524 | return resolved_type; |
| 8521 | type_ensure_zero_bits_known(ira->codegen, resolved_type); | 9525 | type_ensure_zero_bits_known(ira->codegen, resolved_type); |
| ... | @@ -8523,7 +9527,6 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp | ... | @@ -8523,7 +9527,6 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 8523 | return resolved_type; | 9527 | return resolved_type; |
| 8524 | 9528 | ||
| 8525 | 9529 | ||
| 8526 | AstNode *source_node = bin_op_instruction->base.source_node; | ||
| 8527 | switch (resolved_type->id) { | 9530 | switch (resolved_type->id) { |
| 8528 | case TypeTableEntryIdInvalid: | 9531 | case TypeTableEntryIdInvalid: |
| 8529 | zig_unreachable(); // handled above | 9532 | zig_unreachable(); // handled above |
| ... | @@ -8538,7 +9541,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp | ... | @@ -8538,7 +9541,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 8538 | case TypeTableEntryIdMetaType: | 9541 | case TypeTableEntryIdMetaType: |
| 8539 | case TypeTableEntryIdVoid: | 9542 | case TypeTableEntryIdVoid: |
| 8540 | case TypeTableEntryIdPointer: | 9543 | case TypeTableEntryIdPointer: |
| 8541 | case TypeTableEntryIdPureError: | 9544 | case TypeTableEntryIdErrorSet: |
| 8542 | case TypeTableEntryIdFn: | 9545 | case TypeTableEntryIdFn: |
| 8543 | case TypeTableEntryIdOpaque: | 9546 | case TypeTableEntryIdOpaque: |
| 8544 | case TypeTableEntryIdNamespace: | 9547 | case TypeTableEntryIdNamespace: |
| ... | @@ -8692,6 +9695,7 @@ static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val, | ... | @@ -8692,6 +9695,7 @@ static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val, |
| 8692 | case IrBinOpArrayCat: | 9695 | case IrBinOpArrayCat: |
| 8693 | case IrBinOpArrayMult: | 9696 | case IrBinOpArrayMult: |
| 8694 | case IrBinOpRemUnspecified: | 9697 | case IrBinOpRemUnspecified: |
| 9698 | case IrBinOpMergeErrorSets: | ||
| 8695 | zig_unreachable(); | 9699 | zig_unreachable(); |
| 8696 | case IrBinOpBinOr: | 9700 | case IrBinOpBinOr: |
| 8697 | assert(is_int); | 9701 | assert(is_int); |
| ... | @@ -9264,6 +10268,46 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp | ... | @@ -9264,6 +10268,46 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp |
| 9264 | return get_array_type(ira->codegen, child_type, new_array_len); | 10268 | return get_array_type(ira->codegen, child_type, new_array_len); |
| 9265 | } | 10269 | } |
| 9266 | 10270 | ||
| 10271 | static 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 | |||
| 9267 | static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { | 10311 | static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { |
| 9268 | IrBinOp op_id = bin_op_instruction->op_id; | 10312 | IrBinOp op_id = bin_op_instruction->op_id; |
| 9269 | switch (op_id) { | 10313 | switch (op_id) { |
| ... | @@ -9305,6 +10349,8 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi | ... | @@ -9305,6 +10349,8 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi |
| 9305 | return ir_analyze_array_cat(ira, bin_op_instruction); | 10349 | return ir_analyze_array_cat(ira, bin_op_instruction); |
| 9306 | case IrBinOpArrayMult: | 10350 | case IrBinOpArrayMult: |
| 9307 | return ir_analyze_array_mult(ira, bin_op_instruction); | 10351 | return ir_analyze_array_mult(ira, bin_op_instruction); |
| 10352 | case IrBinOpMergeErrorSets: | ||
| 10353 | return ir_analyze_merge_error_sets(ira, bin_op_instruction); | ||
| 9308 | } | 10354 | } |
| 9309 | zig_unreachable(); | 10355 | zig_unreachable(); |
| 9310 | } | 10356 | } |
| ... | @@ -9326,7 +10372,7 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) { | ... | @@ -9326,7 +10372,7 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) { |
| 9326 | case TypeTableEntryIdInt: | 10372 | case TypeTableEntryIdInt: |
| 9327 | case TypeTableEntryIdFloat: | 10373 | case TypeTableEntryIdFloat: |
| 9328 | case TypeTableEntryIdVoid: | 10374 | case TypeTableEntryIdVoid: |
| 9329 | case TypeTableEntryIdPureError: | 10375 | case TypeTableEntryIdErrorSet: |
| 9330 | case TypeTableEntryIdFn: | 10376 | case TypeTableEntryIdFn: |
| 9331 | return VarClassRequiredAny; | 10377 | return VarClassRequiredAny; |
| 9332 | case TypeTableEntryIdNumLitFloat: | 10378 | case TypeTableEntryIdNumLitFloat: |
| ... | @@ -9352,7 +10398,7 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) { | ... | @@ -9352,7 +10398,7 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) { |
| 9352 | case TypeTableEntryIdMaybe: | 10398 | case TypeTableEntryIdMaybe: |
| 9353 | return get_var_class_required(type_entry->data.maybe.child_type); | 10399 | return get_var_class_required(type_entry->data.maybe.child_type); |
| 9354 | case TypeTableEntryIdErrorUnion: | 10400 | case TypeTableEntryIdErrorUnion: |
| 9355 | return get_var_class_required(type_entry->data.error.child_type); | 10401 | return get_var_class_required(type_entry->data.error_union.payload_type); |
| 9356 | 10402 | ||
| 9357 | case TypeTableEntryIdStruct: | 10403 | case TypeTableEntryIdStruct: |
| 9358 | case TypeTableEntryIdEnum: | 10404 | case TypeTableEntryIdEnum: |
| ... | @@ -9587,7 +10633,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi | ... | @@ -9587,7 +10633,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi |
| 9587 | case TypeTableEntryIdNullLit: | 10633 | case TypeTableEntryIdNullLit: |
| 9588 | case TypeTableEntryIdMaybe: | 10634 | case TypeTableEntryIdMaybe: |
| 9589 | case TypeTableEntryIdErrorUnion: | 10635 | case TypeTableEntryIdErrorUnion: |
| 9590 | case TypeTableEntryIdPureError: | 10636 | case TypeTableEntryIdErrorSet: |
| 9591 | case TypeTableEntryIdNamespace: | 10637 | case TypeTableEntryIdNamespace: |
| 9592 | case TypeTableEntryIdBlock: | 10638 | case TypeTableEntryIdBlock: |
| 9593 | case TypeTableEntryIdBoundFn: | 10639 | case TypeTableEntryIdBoundFn: |
| ... | @@ -9610,7 +10656,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi | ... | @@ -9610,7 +10656,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi |
| 9610 | case TypeTableEntryIdNullLit: | 10656 | case TypeTableEntryIdNullLit: |
| 9611 | case TypeTableEntryIdMaybe: | 10657 | case TypeTableEntryIdMaybe: |
| 9612 | case TypeTableEntryIdErrorUnion: | 10658 | case TypeTableEntryIdErrorUnion: |
| 9613 | case TypeTableEntryIdPureError: | 10659 | case TypeTableEntryIdErrorSet: |
| 9614 | zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name)); | 10660 | zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name)); |
| 9615 | case TypeTableEntryIdNamespace: | 10661 | case TypeTableEntryIdNamespace: |
| 9616 | case TypeTableEntryIdBlock: | 10662 | case TypeTableEntryIdBlock: |
| ... | @@ -9644,6 +10690,31 @@ static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, | ... | @@ -9644,6 +10690,31 @@ static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, |
| 9644 | return nullable_type; | 10690 | return nullable_type; |
| 9645 | } | 10691 | } |
| 9646 | 10692 | ||
| 10693 | static 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 | |||
| 9647 | static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, | 10718 | static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, |
| 9648 | IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i) | 10719 | IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i) |
| 9649 | { | 10720 | { |
| ... | @@ -9926,9 +10997,17 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -9926,9 +10997,17 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 9926 | } | 10997 | } |
| 9927 | 10998 | ||
| 9928 | AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; | 10999 | AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; |
| 9929 | TypeTableEntry *return_type = analyze_type_expr(ira->codegen, exec_scope, return_type_node); | 11000 | TypeTableEntry *specified_return_type = analyze_type_expr(ira->codegen, exec_scope, return_type_node); |
| 9930 | if (type_is_invalid(return_type)) | 11001 | if (type_is_invalid(specified_return_type)) |
| 9931 | return ira->codegen->builtin_types.entry_invalid; | 11002 | return ira->codegen->builtin_types.entry_invalid; |
| 11003 | TypeTableEntry *return_type; | ||
| 11004 | TypeTableEntry *inferred_err_set_type = nullptr; | ||
| 11005 | if (fn_proto_node->data.fn_proto.auto_err_set) { | ||
| 11006 | inferred_err_set_type = get_auto_err_set_type(ira->codegen, fn_entry); | ||
| 11007 | return_type = get_error_union_type(ira->codegen, inferred_err_set_type, specified_return_type); | ||
| 11008 | } else { | ||
| 11009 | return_type = specified_return_type; | ||
| 11010 | } | ||
| 9932 | 11011 | ||
| 9933 | IrInstruction *result; | 11012 | IrInstruction *result; |
| 9934 | 11013 | ||
| ... | @@ -9942,6 +11021,23 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -9942,6 +11021,23 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 9942 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, | 11021 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, |
| 9943 | nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec); | 11022 | nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec); |
| 9944 | 11023 | ||
| 11024 | if (inferred_err_set_type != nullptr) { | ||
| 11025 | inferred_err_set_type->data.error_set.infer_fn = nullptr; | ||
| 11026 | if (result->value.type->id == TypeTableEntryIdErrorUnion) { | ||
| 11027 | if (result->value.data.x_err_union.err != nullptr) { | ||
| 11028 | inferred_err_set_type->data.error_set.err_count = 1; | ||
| 11029 | inferred_err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(1); | ||
| 11030 | inferred_err_set_type->data.error_set.errors[0] = result->value.data.x_err_union.err; | ||
| 11031 | } | ||
| 11032 | TypeTableEntry *fn_inferred_err_set_type = result->value.type->data.error_union.err_set_type; | ||
| 11033 | inferred_err_set_type->data.error_set.err_count = fn_inferred_err_set_type->data.error_set.err_count; | ||
| 11034 | inferred_err_set_type->data.error_set.errors = fn_inferred_err_set_type->data.error_set.errors; | ||
| 11035 | } else if (result->value.type->id == TypeTableEntryIdErrorSet) { | ||
| 11036 | inferred_err_set_type->data.error_set.err_count = result->value.type->data.error_set.err_count; | ||
| 11037 | inferred_err_set_type->data.error_set.errors = result->value.type->data.error_set.errors; | ||
| 11038 | } | ||
| 11039 | } | ||
| 11040 | |||
| 9945 | ira->codegen->memoized_fn_eval_table.put(exec_scope, result); | 11041 | ira->codegen->memoized_fn_eval_table.put(exec_scope, result); |
| 9946 | 11042 | ||
| 9947 | if (type_is_invalid(result->value.type)) | 11043 | if (type_is_invalid(result->value.type)) |
| ... | @@ -10092,12 +11188,17 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -10092,12 +11188,17 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 10092 | 11188 | ||
| 10093 | { | 11189 | { |
| 10094 | AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; | 11190 | AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; |
| 10095 | TypeTableEntry *return_type = analyze_type_expr(ira->codegen, impl_fn->child_scope, return_type_node); | 11191 | TypeTableEntry *specified_return_type = analyze_type_expr(ira->codegen, impl_fn->child_scope, return_type_node); |
| 10096 | if (type_is_invalid(return_type)) | 11192 | if (type_is_invalid(specified_return_type)) |
| 10097 | return ira->codegen->builtin_types.entry_invalid; | 11193 | return ira->codegen->builtin_types.entry_invalid; |
| 10098 | inst_fn_type_id.return_type = return_type; | 11194 | if (fn_proto_node->data.fn_proto.auto_err_set) { |
| 11195 | TypeTableEntry *inferred_err_set_type = get_auto_err_set_type(ira->codegen, impl_fn); | ||
| 11196 | inst_fn_type_id.return_type = get_error_union_type(ira->codegen, inferred_err_set_type, specified_return_type); | ||
| 11197 | } else { | ||
| 11198 | inst_fn_type_id.return_type = specified_return_type; | ||
| 11199 | } | ||
| 10099 | 11200 | ||
| 10100 | if (type_requires_comptime(return_type)) { | 11201 | if (type_requires_comptime(specified_return_type)) { |
| 10101 | // Throw out our work and call the function as if it were comptime. | 11202 | // Throw out our work and call the function as if it were comptime. |
| 10102 | return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, FnInlineAuto); | 11203 | return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, FnInlineAuto); |
| 10103 | } | 11204 | } |
| ... | @@ -10128,7 +11229,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -10128,7 +11229,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 10128 | TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type; | 11229 | TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type; |
| 10129 | ir_add_alloca(ira, new_call_instruction, return_type); | 11230 | ir_add_alloca(ira, new_call_instruction, return_type); |
| 10130 | 11231 | ||
| 10131 | if (return_type->id == TypeTableEntryIdPureError || return_type->id == TypeTableEntryIdErrorUnion) { | 11232 | if (return_type->id == TypeTableEntryIdErrorSet || return_type->id == TypeTableEntryIdErrorUnion) { |
| 10132 | parent_fn_entry->calls_errorable_function = true; | 11233 | parent_fn_entry->calls_errorable_function = true; |
| 10133 | } | 11234 | } |
| 10134 | 11235 | ||
| ... | @@ -10138,7 +11239,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -10138,7 +11239,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 10138 | FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec); | 11239 | FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec); |
| 10139 | assert(fn_type_id->return_type != nullptr); | 11240 | assert(fn_type_id->return_type != nullptr); |
| 10140 | assert(parent_fn_entry != nullptr); | 11241 | assert(parent_fn_entry != nullptr); |
| 10141 | if (fn_type_id->return_type->id == TypeTableEntryIdPureError || fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) { | 11242 | if (fn_type_id->return_type->id == TypeTableEntryIdErrorSet || fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) { |
| 10142 | parent_fn_entry->calls_errorable_function = true; | 11243 | parent_fn_entry->calls_errorable_function = true; |
| 10143 | } | 11244 | } |
| 10144 | 11245 | ||
| ... | @@ -10257,58 +11358,6 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction | ... | @@ -10257,58 +11358,6 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction |
| 10257 | } | 11358 | } |
| 10258 | } | 11359 | } |
| 10259 | 11360 | ||
| 10260 | static 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 | |||
| 10312 | static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { | 11361 | static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { |
| 10313 | IrInstruction *value = un_op_instruction->value->other; | 11362 | IrInstruction *value = un_op_instruction->value->other; |
| 10314 | 11363 | ||
| ... | @@ -10364,7 +11413,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op | ... | @@ -10364,7 +11413,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op |
| 10364 | case TypeTableEntryIdNullLit: | 11413 | case TypeTableEntryIdNullLit: |
| 10365 | case TypeTableEntryIdMaybe: | 11414 | case TypeTableEntryIdMaybe: |
| 10366 | case TypeTableEntryIdErrorUnion: | 11415 | case TypeTableEntryIdErrorUnion: |
| 10367 | case TypeTableEntryIdPureError: | 11416 | case TypeTableEntryIdErrorSet: |
| 10368 | case TypeTableEntryIdEnum: | 11417 | case TypeTableEntryIdEnum: |
| 10369 | case TypeTableEntryIdUnion: | 11418 | case TypeTableEntryIdUnion: |
| 10370 | case TypeTableEntryIdFn: | 11419 | case TypeTableEntryIdFn: |
| ... | @@ -10474,8 +11523,6 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio | ... | @@ -10474,8 +11523,6 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio |
| 10474 | return ir_analyze_dereference(ira, un_op_instruction); | 11523 | return ir_analyze_dereference(ira, un_op_instruction); |
| 10475 | case IrUnOpMaybe: | 11524 | case IrUnOpMaybe: |
| 10476 | return ir_analyze_maybe(ira, un_op_instruction); | 11525 | return ir_analyze_maybe(ira, un_op_instruction); |
| 10477 | case IrUnOpError: | ||
| 10478 | return ir_analyze_unary_prefix_op_err(ira, un_op_instruction); | ||
| 10479 | } | 11526 | } |
| 10480 | zig_unreachable(); | 11527 | zig_unreachable(); |
| 10481 | } | 11528 | } |
| ... | @@ -10633,6 +11680,9 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP | ... | @@ -10633,6 +11680,9 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP |
| 10633 | IrInstruction *branch_instruction = predecessor->instruction_list.pop(); | 11680 | IrInstruction *branch_instruction = predecessor->instruction_list.pop(); |
| 10634 | ir_set_cursor_at_end(&ira->new_irb, predecessor); | 11681 | ir_set_cursor_at_end(&ira->new_irb, predecessor); |
| 10635 | IrInstruction *casted_value = ir_implicit_cast(ira, new_value, resolved_type); | 11682 | IrInstruction *casted_value = ir_implicit_cast(ira, new_value, resolved_type); |
| 11683 | if (casted_value == ira->codegen->invalid_instruction) { | ||
| 11684 | return ira->codegen->builtin_types.entry_invalid; | ||
| 11685 | } | ||
| 10636 | new_incoming_values.items[i] = casted_value; | 11686 | new_incoming_values.items[i] = casted_value; |
| 10637 | predecessor->instruction_list.append(branch_instruction); | 11687 | predecessor->instruction_list.append(branch_instruction); |
| 10638 | 11688 | ||
| ... | @@ -11048,6 +12098,25 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field | ... | @@ -11048,6 +12098,25 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field |
| 11048 | } | 12098 | } |
| 11049 | } | 12099 | } |
| 11050 | 12100 | ||
| 12101 | static 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 | |||
| 11051 | static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) { | 12120 | static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) { |
| 11052 | bool pointer_only = false; | 12121 | bool pointer_only = false; |
| 11053 | resolve_top_level_decl(ira->codegen, tld, pointer_only, source_instruction->source_node); | 12122 | resolve_top_level_decl(ira->codegen, tld, pointer_only, source_instruction->source_node); |
| ... | @@ -11063,7 +12132,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source | ... | @@ -11063,7 +12132,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source |
| 11063 | TldVar *tld_var = (TldVar *)tld; | 12132 | TldVar *tld_var = (TldVar *)tld; |
| 11064 | VariableTableEntry *var = tld_var->var; | 12133 | VariableTableEntry *var = tld_var->var; |
| 11065 | if (tld_var->extern_lib_name != nullptr) { | 12134 | if (tld_var->extern_lib_name != nullptr) { |
| 11066 | add_link_lib_symbol(ira->codegen, tld_var->extern_lib_name, &var->name); | 12135 | add_link_lib_symbol(ira, tld_var->extern_lib_name, &var->name, source_instruction->source_node); |
| 11067 | } | 12136 | } |
| 11068 | 12137 | ||
| 11069 | return ir_analyze_var_ptr(ira, source_instruction, var, false, false); | 12138 | return ir_analyze_var_ptr(ira, source_instruction, var, false, false); |
| ... | @@ -11085,7 +12154,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source | ... | @@ -11085,7 +12154,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source |
| 11085 | const_val->data.x_fn.fn_entry = fn_entry; | 12154 | const_val->data.x_fn.fn_entry = fn_entry; |
| 11086 | 12155 | ||
| 11087 | if (tld_fn->extern_lib_name != nullptr) { | 12156 | if (tld_fn->extern_lib_name != nullptr) { |
| 11088 | add_link_lib_symbol(ira->codegen, tld_fn->extern_lib_name, &fn_entry->symbol_name); | 12157 | add_link_lib_symbol(ira, tld_fn->extern_lib_name, &fn_entry->symbol_name, source_instruction->source_node); |
| 11089 | } | 12158 | } |
| 11090 | 12159 | ||
| 11091 | bool ptr_is_const = true; | 12160 | bool ptr_is_const = true; |
| ... | @@ -11097,6 +12166,17 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source | ... | @@ -11097,6 +12166,17 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source |
| 11097 | zig_unreachable(); | 12166 | zig_unreachable(); |
| 11098 | } | 12167 | } |
| 11099 | 12168 | ||
| 12169 | static 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 | |||
| 11100 | static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstructionFieldPtr *field_ptr_instruction) { | 12180 | static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstructionFieldPtr *field_ptr_instruction) { |
| 11101 | IrInstruction *container_ptr = field_ptr_instruction->container_ptr->other; | 12181 | IrInstruction *container_ptr = field_ptr_instruction->container_ptr->other; |
| 11102 | if (type_is_invalid(container_ptr->value.type)) | 12182 | if (type_is_invalid(container_ptr->value.type)) |
| ... | @@ -11238,23 +12318,52 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru | ... | @@ -11238,23 +12318,52 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru |
| 11238 | buf_sprintf("container '%s' has no member called '%s'", | 12318 | buf_sprintf("container '%s' has no member called '%s'", |
| 11239 | buf_ptr(&child_type->name), buf_ptr(field_name))); | 12319 | buf_ptr(&child_type->name), buf_ptr(field_name))); |
| 11240 | return ira->codegen->builtin_types.entry_invalid; | 12320 | return ira->codegen->builtin_types.entry_invalid; |
| 11241 | } else if (child_type->id == TypeTableEntryIdPureError) { | 12321 | } else if (child_type->id == TypeTableEntryIdErrorSet) { |
| 11242 | auto err_table_entry = ira->codegen->error_table.maybe_get(field_name); | 12322 | ErrorTableEntry *err_entry; |
| 11243 | if (err_table_entry) { | 12323 | TypeTableEntry *err_set_type; |
| 11244 | ConstExprValue *const_val = create_const_vals(1); | 12324 | if (type_is_global_error_set(child_type)) { |
| 11245 | const_val->special = ConstValSpecialStatic; | 12325 | auto existing_entry = ira->codegen->error_table.maybe_get(field_name); |
| 11246 | const_val->type = child_type; | 12326 | if (existing_entry) { |
| 11247 | const_val->data.x_pure_err = err_table_entry->value; | 12327 | err_entry = existing_entry->value; |
| 11248 | 12328 | } else { | |
| 11249 | bool ptr_is_const = true; | 12329 | err_entry = allocate<ErrorTableEntry>(1); |
| 11250 | bool ptr_is_volatile = false; | 12330 | err_entry->decl_node = field_ptr_instruction->base.source_node; |
| 11251 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val, | 12331 | buf_init_from_buf(&err_entry->name, field_name); |
| 11252 | child_type, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); | 12332 | size_t error_value_count = ira->codegen->errors_by_index.length; |
| 12333 | assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ira->codegen->err_tag_type->data.integral.bit_count)); | ||
| 12334 | err_entry->value = error_value_count; | ||
| 12335 | ira->codegen->errors_by_index.append(err_entry); | ||
| 12336 | ira->codegen->err_enumerators.append(ZigLLVMCreateDebugEnumerator(ira->codegen->dbuilder, | ||
| 12337 | buf_ptr(field_name), error_value_count)); | ||
| 12338 | ira->codegen->error_table.put(field_name, err_entry); | ||
| 12339 | } | ||
| 12340 | if (err_entry->set_with_only_this_in_it == nullptr) { | ||
| 12341 | err_entry->set_with_only_this_in_it = make_err_set_with_one_item(ira->codegen, | ||
| 12342 | field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, | ||
| 12343 | err_entry); | ||
| 12344 | } | ||
| 12345 | err_set_type = err_entry->set_with_only_this_in_it; | ||
| 12346 | } else { | ||
| 12347 | if (!resolve_inferred_error_set(ira, child_type, field_ptr_instruction->base.source_node)) { | ||
| 12348 | return ira->codegen->builtin_types.entry_invalid; | ||
| 12349 | } | ||
| 12350 | err_entry = find_err_table_entry(child_type, field_name); | ||
| 12351 | if (err_entry == nullptr) { | ||
| 12352 | ir_add_error(ira, &field_ptr_instruction->base, | ||
| 12353 | buf_sprintf("no error named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&child_type->name))); | ||
| 12354 | return ira->codegen->builtin_types.entry_invalid; | ||
| 12355 | } | ||
| 12356 | err_set_type = child_type; | ||
| 11253 | } | 12357 | } |
| 12358 | ConstExprValue *const_val = create_const_vals(1); | ||
| 12359 | const_val->special = ConstValSpecialStatic; | ||
| 12360 | const_val->type = err_set_type; | ||
| 12361 | const_val->data.x_err_set = err_entry; | ||
| 11254 | 12362 | ||
| 11255 | ir_add_error(ira, &field_ptr_instruction->base, | 12363 | bool ptr_is_const = true; |
| 11256 | buf_sprintf("use of undeclared error value '%s'", buf_ptr(field_name))); | 12364 | bool ptr_is_volatile = false; |
| 11257 | return ira->codegen->builtin_types.entry_invalid; | 12365 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val, |
| 12366 | err_set_type, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); | ||
| 11258 | } else if (child_type->id == TypeTableEntryIdInt) { | 12367 | } else if (child_type->id == TypeTableEntryIdInt) { |
| 11259 | if (buf_eql_str(field_name, "bit_count")) { | 12368 | if (buf_eql_str(field_name, "bit_count")) { |
| 11260 | bool ptr_is_const = true; | 12369 | bool ptr_is_const = true; |
| ... | @@ -11337,11 +12446,18 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru | ... | @@ -11337,11 +12446,18 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru |
| 11337 | return ira->codegen->builtin_types.entry_invalid; | 12446 | return ira->codegen->builtin_types.entry_invalid; |
| 11338 | } | 12447 | } |
| 11339 | } else if (child_type->id == TypeTableEntryIdErrorUnion) { | 12448 | } else if (child_type->id == TypeTableEntryIdErrorUnion) { |
| 11340 | if (buf_eql_str(field_name, "Child")) { | 12449 | if (buf_eql_str(field_name, "Payload")) { |
| 12450 | bool ptr_is_const = true; | ||
| 12451 | bool ptr_is_volatile = false; | ||
| 12452 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, | ||
| 12453 | create_const_type(ira->codegen, child_type->data.error_union.payload_type), | ||
| 12454 | ira->codegen->builtin_types.entry_type, | ||
| 12455 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); | ||
| 12456 | } else if (buf_eql_str(field_name, "ErrorSet")) { | ||
| 11341 | bool ptr_is_const = true; | 12457 | bool ptr_is_const = true; |
| 11342 | bool ptr_is_volatile = false; | 12458 | bool ptr_is_volatile = false; |
| 11343 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, | 12459 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, |
| 11344 | create_const_type(ira->codegen, child_type->data.error.child_type), | 12460 | create_const_type(ira->codegen, child_type->data.error_union.err_set_type), |
| 11345 | ira->codegen->builtin_types.entry_type, | 12461 | ira->codegen->builtin_types.entry_type, |
| 11346 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); | 12462 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); |
| 11347 | } else { | 12463 | } else { |
| ... | @@ -11528,7 +12644,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi | ... | @@ -11528,7 +12644,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi |
| 11528 | case TypeTableEntryIdStruct: | 12644 | case TypeTableEntryIdStruct: |
| 11529 | case TypeTableEntryIdMaybe: | 12645 | case TypeTableEntryIdMaybe: |
| 11530 | case TypeTableEntryIdErrorUnion: | 12646 | case TypeTableEntryIdErrorUnion: |
| 11531 | case TypeTableEntryIdPureError: | 12647 | case TypeTableEntryIdErrorSet: |
| 11532 | case TypeTableEntryIdEnum: | 12648 | case TypeTableEntryIdEnum: |
| 11533 | case TypeTableEntryIdUnion: | 12649 | case TypeTableEntryIdUnion: |
| 11534 | case TypeTableEntryIdFn: | 12650 | case TypeTableEntryIdFn: |
| ... | @@ -11795,7 +12911,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, | ... | @@ -11795,7 +12911,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, |
| 11795 | case TypeTableEntryIdNumLitInt: | 12911 | case TypeTableEntryIdNumLitInt: |
| 11796 | case TypeTableEntryIdMaybe: | 12912 | case TypeTableEntryIdMaybe: |
| 11797 | case TypeTableEntryIdErrorUnion: | 12913 | case TypeTableEntryIdErrorUnion: |
| 11798 | case TypeTableEntryIdPureError: | 12914 | case TypeTableEntryIdErrorSet: |
| 11799 | case TypeTableEntryIdEnum: | 12915 | case TypeTableEntryIdEnum: |
| 11800 | case TypeTableEntryIdUnion: | 12916 | case TypeTableEntryIdUnion: |
| 11801 | case TypeTableEntryIdFn: | 12917 | case TypeTableEntryIdFn: |
| ... | @@ -11903,7 +13019,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira, | ... | @@ -11903,7 +13019,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira, |
| 11903 | case TypeTableEntryIdNumLitInt: | 13019 | case TypeTableEntryIdNumLitInt: |
| 11904 | case TypeTableEntryIdMaybe: | 13020 | case TypeTableEntryIdMaybe: |
| 11905 | case TypeTableEntryIdErrorUnion: | 13021 | case TypeTableEntryIdErrorUnion: |
| 11906 | case TypeTableEntryIdPureError: | 13022 | case TypeTableEntryIdErrorSet: |
| 11907 | case TypeTableEntryIdEnum: | 13023 | case TypeTableEntryIdEnum: |
| 11908 | case TypeTableEntryIdUnion: | 13024 | case TypeTableEntryIdUnion: |
| 11909 | case TypeTableEntryIdFn: | 13025 | case TypeTableEntryIdFn: |
| ... | @@ -11956,7 +13072,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, | ... | @@ -11956,7 +13072,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 11956 | case TypeTableEntryIdStruct: | 13072 | case TypeTableEntryIdStruct: |
| 11957 | case TypeTableEntryIdMaybe: | 13073 | case TypeTableEntryIdMaybe: |
| 11958 | case TypeTableEntryIdErrorUnion: | 13074 | case TypeTableEntryIdErrorUnion: |
| 11959 | case TypeTableEntryIdPureError: | 13075 | case TypeTableEntryIdErrorSet: |
| 11960 | case TypeTableEntryIdEnum: | 13076 | case TypeTableEntryIdEnum: |
| 11961 | case TypeTableEntryIdUnion: | 13077 | case TypeTableEntryIdUnion: |
| 11962 | case TypeTableEntryIdFn: | 13078 | case TypeTableEntryIdFn: |
| ... | @@ -12291,7 +13407,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, | ... | @@ -12291,7 +13407,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 12291 | case TypeTableEntryIdPointer: | 13407 | case TypeTableEntryIdPointer: |
| 12292 | case TypeTableEntryIdFn: | 13408 | case TypeTableEntryIdFn: |
| 12293 | case TypeTableEntryIdNamespace: | 13409 | case TypeTableEntryIdNamespace: |
| 12294 | case TypeTableEntryIdPureError: | 13410 | case TypeTableEntryIdErrorSet: |
| 12295 | if (pointee_val) { | 13411 | if (pointee_val) { |
| 12296 | ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base); | 13412 | ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base); |
| 12297 | copy_const_val(out_val, pointee_val, true); | 13413 | copy_const_val(out_val, pointee_val, true); |
| ... | @@ -12361,8 +13477,6 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, | ... | @@ -12361,8 +13477,6 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 12361 | return target_type; | 13477 | return target_type; |
| 12362 | } | 13478 | } |
| 12363 | case TypeTableEntryIdErrorUnion: | 13479 | case TypeTableEntryIdErrorUnion: |
| 12364 | // see https://github.com/andrewrk/zig/issues/632 | ||
| 12365 | zig_panic("TODO switch on error union"); | ||
| 12366 | case TypeTableEntryIdUnreachable: | 13480 | case TypeTableEntryIdUnreachable: |
| 12367 | case TypeTableEntryIdArray: | 13481 | case TypeTableEntryIdArray: |
| 12368 | case TypeTableEntryIdStruct: | 13482 | case TypeTableEntryIdStruct: |
| ... | @@ -12887,7 +14001,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ | ... | @@ -12887,7 +14001,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ |
| 12887 | case TypeTableEntryIdNullLit: | 14001 | case TypeTableEntryIdNullLit: |
| 12888 | case TypeTableEntryIdMaybe: | 14002 | case TypeTableEntryIdMaybe: |
| 12889 | case TypeTableEntryIdErrorUnion: | 14003 | case TypeTableEntryIdErrorUnion: |
| 12890 | case TypeTableEntryIdPureError: | 14004 | case TypeTableEntryIdErrorSet: |
| 12891 | case TypeTableEntryIdUnion: | 14005 | case TypeTableEntryIdUnion: |
| 12892 | case TypeTableEntryIdFn: | 14006 | case TypeTableEntryIdFn: |
| 12893 | case TypeTableEntryIdNamespace: | 14007 | case TypeTableEntryIdNamespace: |
| ... | @@ -12975,7 +14089,7 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc | ... | @@ -12975,7 +14089,7 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc |
| 12975 | TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true); | 14089 | TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true); |
| 12976 | TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type); | 14090 | TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type); |
| 12977 | if (casted_value->value.special == ConstValSpecialStatic) { | 14091 | if (casted_value->value.special == ConstValSpecialStatic) { |
| 12978 | ErrorTableEntry *err = casted_value->value.data.x_pure_err; | 14092 | ErrorTableEntry *err = casted_value->value.data.x_err_set; |
| 12979 | if (!err->cached_error_name_val) { | 14093 | if (!err->cached_error_name_val) { |
| 12980 | ConstExprValue *array_val = create_const_str_lit(ira->codegen, &err->name); | 14094 | ConstExprValue *array_val = create_const_str_lit(ira->codegen, &err->name); |
| 12981 | err->cached_error_name_val = create_const_slice(ira->codegen, array_val, 0, buf_len(&err->name), true); | 14095 | err->cached_error_name_val = create_const_slice(ira->codegen, array_val, 0, buf_len(&err->name), true); |
| ... | @@ -13956,6 +15070,15 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns | ... | @@ -13956,6 +15070,15 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns |
| 13956 | result = container_type->data.structure.src_field_count; | 15070 | result = container_type->data.structure.src_field_count; |
| 13957 | } else if (container_type->id == TypeTableEntryIdUnion) { | 15071 | } else if (container_type->id == TypeTableEntryIdUnion) { |
| 13958 | result = container_type->data.unionation.src_field_count; | 15072 | result = container_type->data.unionation.src_field_count; |
| 15073 | } else if (container_type->id == TypeTableEntryIdErrorSet) { | ||
| 15074 | if (!resolve_inferred_error_set(ira, container_type, instruction->base.source_node)) { | ||
| 15075 | return ira->codegen->builtin_types.entry_invalid; | ||
| 15076 | } | ||
| 15077 | if (type_is_global_error_set(container_type)) { | ||
| 15078 | ir_add_error(ira, &instruction->base, buf_sprintf("global error set member count not available at comptime")); | ||
| 15079 | return ira->codegen->builtin_types.entry_invalid; | ||
| 15080 | } | ||
| 15081 | result = container_type->data.error_set.err_count; | ||
| 13959 | } else { | 15082 | } else { |
| 13960 | ir_add_error(ira, &instruction->base, buf_sprintf("no value count available for type '%s'", buf_ptr(&container_type->name))); | 15083 | ir_add_error(ira, &instruction->base, buf_sprintf("no value count available for type '%s'", buf_ptr(&container_type->name))); |
| 13961 | return ira->codegen->builtin_types.entry_invalid; | 15084 | return ira->codegen->builtin_types.entry_invalid; |
| ... | @@ -14120,7 +15243,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc | ... | @@ -14120,7 +15243,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc |
| 14120 | case TypeTableEntryIdStruct: | 15243 | case TypeTableEntryIdStruct: |
| 14121 | case TypeTableEntryIdMaybe: | 15244 | case TypeTableEntryIdMaybe: |
| 14122 | case TypeTableEntryIdErrorUnion: | 15245 | case TypeTableEntryIdErrorUnion: |
| 14123 | case TypeTableEntryIdPureError: | 15246 | case TypeTableEntryIdErrorSet: |
| 14124 | case TypeTableEntryIdEnum: | 15247 | case TypeTableEntryIdEnum: |
| 14125 | case TypeTableEntryIdUnion: | 15248 | case TypeTableEntryIdUnion: |
| 14126 | case TypeTableEntryIdFn: | 15249 | case TypeTableEntryIdFn: |
| ... | @@ -14251,9 +15374,22 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc | ... | @@ -14251,9 +15374,22 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc |
| 14251 | } | 15374 | } |
| 14252 | } | 15375 | } |
| 14253 | 15376 | ||
| 15377 | TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type; | ||
| 15378 | if (!resolve_inferred_error_set(ira, err_set_type, instruction->base.source_node)) { | ||
| 15379 | return ira->codegen->builtin_types.entry_invalid; | ||
| 15380 | } | ||
| 15381 | if (!type_is_global_error_set(err_set_type) && | ||
| 15382 | err_set_type->data.error_set.err_count == 0) | ||
| 15383 | { | ||
| 15384 | assert(err_set_type->data.error_set.infer_fn == nullptr); | ||
| 15385 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | ||
| 15386 | out_val->data.x_bool = false; | ||
| 15387 | return ira->codegen->builtin_types.entry_bool; | ||
| 15388 | } | ||
| 15389 | |||
| 14254 | ir_build_test_err_from(&ira->new_irb, &instruction->base, value); | 15390 | ir_build_test_err_from(&ira->new_irb, &instruction->base, value); |
| 14255 | return ira->codegen->builtin_types.entry_bool; | 15391 | return ira->codegen->builtin_types.entry_bool; |
| 14256 | } else if (type_entry->id == TypeTableEntryIdPureError) { | 15392 | } else if (type_entry->id == TypeTableEntryIdErrorSet) { |
| 14257 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | 15393 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 14258 | out_val->data.x_bool = true; | 15394 | out_val->data.x_bool = true; |
| 14259 | return ira->codegen->builtin_types.entry_bool; | 15395 | return ira->codegen->builtin_types.entry_bool; |
| ... | @@ -14289,13 +15425,13 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, | ... | @@ -14289,13 +15425,13 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, |
| 14289 | assert(err); | 15425 | assert(err); |
| 14290 | 15426 | ||
| 14291 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | 15427 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 14292 | out_val->data.x_pure_err = err; | 15428 | out_val->data.x_err_set = err; |
| 14293 | return ira->codegen->builtin_types.entry_pure_error; | 15429 | return type_entry->data.error_union.err_set_type; |
| 14294 | } | 15430 | } |
| 14295 | } | 15431 | } |
| 14296 | 15432 | ||
| 14297 | ir_build_unwrap_err_code_from(&ira->new_irb, &instruction->base, value); | 15433 | ir_build_unwrap_err_code_from(&ira->new_irb, &instruction->base, value); |
| 14298 | return ira->codegen->builtin_types.entry_pure_error; | 15434 | return type_entry->data.error_union.err_set_type; |
| 14299 | } else { | 15435 | } else { |
| 14300 | ir_add_error(ira, value, | 15436 | ir_add_error(ira, value, |
| 14301 | buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); | 15437 | buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); |
| ... | @@ -14319,10 +15455,10 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, | ... | @@ -14319,10 +15455,10 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, |
| 14319 | if (type_is_invalid(type_entry)) { | 15455 | if (type_is_invalid(type_entry)) { |
| 14320 | return ira->codegen->builtin_types.entry_invalid; | 15456 | return ira->codegen->builtin_types.entry_invalid; |
| 14321 | } else if (type_entry->id == TypeTableEntryIdErrorUnion) { | 15457 | } else if (type_entry->id == TypeTableEntryIdErrorUnion) { |
| 14322 | TypeTableEntry *child_type = type_entry->data.error.child_type; | 15458 | TypeTableEntry *payload_type = type_entry->data.error_union.payload_type; |
| 14323 | TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, child_type, | 15459 | TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, payload_type, |
| 14324 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, | 15460 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, |
| 14325 | get_abi_alignment(ira->codegen, child_type), 0, 0); | 15461 | get_abi_alignment(ira->codegen, payload_type), 0, 0); |
| 14326 | if (instr_is_comptime(value)) { | 15462 | if (instr_is_comptime(value)) { |
| 14327 | ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); | 15463 | ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); |
| 14328 | if (!ptr_val) | 15464 | if (!ptr_val) |
| ... | @@ -14332,7 +15468,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, | ... | @@ -14332,7 +15468,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, |
| 14332 | ErrorTableEntry *err = err_union_val->data.x_err_union.err; | 15468 | ErrorTableEntry *err = err_union_val->data.x_err_union.err; |
| 14333 | if (err != nullptr) { | 15469 | if (err != nullptr) { |
| 14334 | ir_add_error(ira, &instruction->base, | 15470 | ir_add_error(ira, &instruction->base, |
| 14335 | buf_sprintf("unable to unwrap error '%s'", buf_ptr(&err->name))); | 15471 | buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name))); |
| 14336 | return ira->codegen->builtin_types.entry_invalid; | 15472 | return ira->codegen->builtin_types.entry_invalid; |
| 14337 | } | 15473 | } |
| 14338 | 15474 | ||
| ... | @@ -14357,6 +15493,12 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc | ... | @@ -14357,6 +15493,12 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc |
| 14357 | AstNode *proto_node = instruction->base.source_node; | 15493 | AstNode *proto_node = instruction->base.source_node; |
| 14358 | assert(proto_node->type == NodeTypeFnProto); | 15494 | assert(proto_node->type == NodeTypeFnProto); |
| 14359 | 15495 | ||
| 15496 | if (proto_node->data.fn_proto.auto_err_set) { | ||
| 15497 | ir_add_error(ira, &instruction->base, | ||
| 15498 | buf_sprintf("inferring error set of return type valid only for function definitions")); | ||
| 15499 | return ira->codegen->builtin_types.entry_invalid; | ||
| 15500 | } | ||
| 15501 | |||
| 14360 | FnTypeId fn_type_id = {0}; | 15502 | FnTypeId fn_type_id = {0}; |
| 14361 | init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length); | 15503 | init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length); |
| 14362 | 15504 | ||
| ... | @@ -14482,6 +15624,57 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira | ... | @@ -14482,6 +15624,57 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira |
| 14482 | } | 15624 | } |
| 14483 | } | 15625 | } |
| 14484 | } | 15626 | } |
| 15627 | } else if (switch_type->id == TypeTableEntryIdErrorSet) { | ||
| 15628 | if (!resolve_inferred_error_set(ira, switch_type, target_value->source_node)) { | ||
| 15629 | return ira->codegen->builtin_types.entry_invalid; | ||
| 15630 | } | ||
| 15631 | |||
| 15632 | AstNode **field_prev_uses = allocate<AstNode *>(ira->codegen->errors_by_index.length); | ||
| 15633 | |||
| 15634 | for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { | ||
| 15635 | IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i]; | ||
| 15636 | |||
| 15637 | IrInstruction *start_value = range->start->other; | ||
| 15638 | if (type_is_invalid(start_value->value.type)) | ||
| 15639 | return ira->codegen->builtin_types.entry_invalid; | ||
| 15640 | |||
| 15641 | IrInstruction *end_value = range->end->other; | ||
| 15642 | if (type_is_invalid(end_value->value.type)) | ||
| 15643 | return ira->codegen->builtin_types.entry_invalid; | ||
| 15644 | |||
| 15645 | assert(start_value->value.type->id == TypeTableEntryIdErrorSet); | ||
| 15646 | uint32_t start_index = start_value->value.data.x_err_set->value; | ||
| 15647 | |||
| 15648 | assert(end_value->value.type->id == TypeTableEntryIdErrorSet); | ||
| 15649 | uint32_t end_index = end_value->value.data.x_err_set->value; | ||
| 15650 | |||
| 15651 | if (start_index != end_index) { | ||
| 15652 | ir_add_error(ira, end_value, buf_sprintf("ranges not allowed when switching on errors")); | ||
| 15653 | return ira->codegen->builtin_types.entry_invalid; | ||
| 15654 | } | ||
| 15655 | |||
| 15656 | AstNode *prev_node = field_prev_uses[start_index]; | ||
| 15657 | if (prev_node != nullptr) { | ||
| 15658 | Buf *err_name = &ira->codegen->errors_by_index.at(start_index)->name; | ||
| 15659 | ErrorMsg *msg = ir_add_error(ira, start_value, | ||
| 15660 | buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&switch_type->name), buf_ptr(err_name))); | ||
| 15661 | add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value is here")); | ||
| 15662 | } | ||
| 15663 | field_prev_uses[start_index] = start_value->source_node; | ||
| 15664 | } | ||
| 15665 | if (!instruction->have_else_prong) { | ||
| 15666 | for (uint32_t i = 0; i < switch_type->data.error_set.err_count; i += 1) { | ||
| 15667 | ErrorTableEntry *err_entry = switch_type->data.error_set.errors[i]; | ||
| 15668 | |||
| 15669 | AstNode *prev_node = field_prev_uses[err_entry->value]; | ||
| 15670 | if (prev_node == nullptr) { | ||
| 15671 | ir_add_error(ira, &instruction->base, | ||
| 15672 | buf_sprintf("error.%s not handled in switch", buf_ptr(&err_entry->name))); | ||
| 15673 | } | ||
| 15674 | } | ||
| 15675 | } | ||
| 15676 | |||
| 15677 | free(field_prev_uses); | ||
| 14485 | } else if (switch_type->id == TypeTableEntryIdInt) { | 15678 | } else if (switch_type->id == TypeTableEntryIdInt) { |
| 14486 | RangeSet rs = {0}; | 15679 | RangeSet rs = {0}; |
| 14487 | for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { | 15680 | for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { |
| ... | @@ -14774,7 +15967,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue | ... | @@ -14774,7 +15967,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue |
| 14774 | zig_panic("TODO buf_write_value_bytes maybe type"); | 15967 | zig_panic("TODO buf_write_value_bytes maybe type"); |
| 14775 | case TypeTableEntryIdErrorUnion: | 15968 | case TypeTableEntryIdErrorUnion: |
| 14776 | zig_panic("TODO buf_write_value_bytes error union"); | 15969 | zig_panic("TODO buf_write_value_bytes error union"); |
| 14777 | case TypeTableEntryIdPureError: | 15970 | case TypeTableEntryIdErrorSet: |
| 14778 | zig_panic("TODO buf_write_value_bytes pure error type"); | 15971 | zig_panic("TODO buf_write_value_bytes pure error type"); |
| 14779 | case TypeTableEntryIdEnum: | 15972 | case TypeTableEntryIdEnum: |
| 14780 | zig_panic("TODO buf_write_value_bytes enum type"); | 15973 | zig_panic("TODO buf_write_value_bytes enum type"); |
| ... | @@ -14832,7 +16025,7 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue | ... | @@ -14832,7 +16025,7 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue |
| 14832 | zig_panic("TODO buf_read_value_bytes maybe type"); | 16025 | zig_panic("TODO buf_read_value_bytes maybe type"); |
| 14833 | case TypeTableEntryIdErrorUnion: | 16026 | case TypeTableEntryIdErrorUnion: |
| 14834 | zig_panic("TODO buf_read_value_bytes error union"); | 16027 | zig_panic("TODO buf_read_value_bytes error union"); |
| 14835 | case TypeTableEntryIdPureError: | 16028 | case TypeTableEntryIdErrorSet: |
| 14836 | zig_panic("TODO buf_read_value_bytes pure error type"); | 16029 | zig_panic("TODO buf_read_value_bytes pure error type"); |
| 14837 | case TypeTableEntryIdEnum: | 16030 | case TypeTableEntryIdEnum: |
| 14838 | zig_panic("TODO buf_read_value_bytes enum type"); | 16031 | zig_panic("TODO buf_read_value_bytes enum type"); |
| ... | @@ -15010,7 +16203,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira, | ... | @@ -15010,7 +16203,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira, |
| 15010 | return ira->codegen->builtin_types.entry_invalid; | 16203 | return ira->codegen->builtin_types.entry_invalid; |
| 15011 | 16204 | ||
| 15012 | if (tld_var->extern_lib_name != nullptr) { | 16205 | if (tld_var->extern_lib_name != nullptr) { |
| 15013 | add_link_lib_symbol(ira->codegen, tld_var->extern_lib_name, &var->name); | 16206 | add_link_lib_symbol(ira, tld_var->extern_lib_name, &var->name, instruction->base.source_node); |
| 15014 | } | 16207 | } |
| 15015 | 16208 | ||
| 15016 | if (lval.is_ptr) { | 16209 | if (lval.is_ptr) { |
| ... | @@ -15029,7 +16222,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira, | ... | @@ -15029,7 +16222,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira, |
| 15029 | assert(fn_entry->type_entry); | 16222 | assert(fn_entry->type_entry); |
| 15030 | 16223 | ||
| 15031 | if (tld_fn->extern_lib_name != nullptr) { | 16224 | if (tld_fn->extern_lib_name != nullptr) { |
| 15032 | add_link_lib_symbol(ira->codegen, tld_fn->extern_lib_name, &fn_entry->symbol_name); | 16225 | add_link_lib_symbol(ira, tld_fn->extern_lib_name, &fn_entry->symbol_name, instruction->base.source_node); |
| 15033 | } | 16226 | } |
| 15034 | 16227 | ||
| 15035 | IrInstruction *ref_instruction = ir_create_const_fn(&ira->new_irb, instruction->base.scope, | 16228 | IrInstruction *ref_instruction = ir_create_const_fn(&ira->new_irb, instruction->base.scope, |
| ... | @@ -15443,6 +16636,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -15443,6 +16636,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 15443 | return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction); | 16636 | return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction); |
| 15444 | case IrInstructionIdErrorReturnTrace: | 16637 | case IrInstructionIdErrorReturnTrace: |
| 15445 | return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction); | 16638 | return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction); |
| 16639 | case IrInstructionIdErrorUnion: | ||
| 16640 | return ir_analyze_instruction_error_union(ira, (IrInstructionErrorUnion *)instruction); | ||
| 15446 | } | 16641 | } |
| 15447 | zig_unreachable(); | 16642 | zig_unreachable(); |
| 15448 | } | 16643 | } |
| ... | @@ -15628,6 +16823,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -15628,6 +16823,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 15628 | case IrInstructionIdArgType: | 16823 | case IrInstructionIdArgType: |
| 15629 | case IrInstructionIdTagType: | 16824 | case IrInstructionIdTagType: |
| 15630 | case IrInstructionIdErrorReturnTrace: | 16825 | case IrInstructionIdErrorReturnTrace: |
| 16826 | case IrInstructionIdErrorUnion: | ||
| 15631 | return false; | 16827 | return false; |
| 15632 | case IrInstructionIdAsm: | 16828 | case IrInstructionIdAsm: |
| 15633 | { | 16829 | { |
src/ir_print.cpp+10-2| ... | @@ -130,6 +130,8 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) { | ... | @@ -130,6 +130,8 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) { |
| 130 | return "++"; | 130 | return "++"; |
| 131 | case IrBinOpArrayMult: | 131 | case IrBinOpArrayMult: |
| 132 | return "**"; | 132 | return "**"; |
| 133 | case IrBinOpMergeErrorSets: | ||
| 134 | return "||"; | ||
| 133 | } | 135 | } |
| 134 | zig_unreachable(); | 136 | zig_unreachable(); |
| 135 | } | 137 | } |
| ... | @@ -148,8 +150,6 @@ static const char *ir_un_op_id_str(IrUnOp op_id) { | ... | @@ -148,8 +150,6 @@ static const char *ir_un_op_id_str(IrUnOp op_id) { |
| 148 | return "*"; | 150 | return "*"; |
| 149 | case IrUnOpMaybe: | 151 | case IrUnOpMaybe: |
| 150 | return "?"; | 152 | return "?"; |
| 151 | case IrUnOpError: | ||
| 152 | return "%"; | ||
| 153 | } | 153 | } |
| 154 | zig_unreachable(); | 154 | zig_unreachable(); |
| 155 | } | 155 | } |
| ... | @@ -1004,6 +1004,11 @@ static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTr | ... | @@ -1004,6 +1004,11 @@ static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTr |
| 1004 | fprintf(irp->f, "@errorReturnTrace()"); | 1004 | fprintf(irp->f, "@errorReturnTrace()"); |
| 1005 | } | 1005 | } |
| 1006 | 1006 | ||
| 1007 | static 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 | } | ||
| 1007 | 1012 | ||
| 1008 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | 1013 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1009 | ir_print_prefix(irp, instruction); | 1014 | ir_print_prefix(irp, instruction); |
| ... | @@ -1322,6 +1327,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1322,6 +1327,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1322 | case IrInstructionIdErrorReturnTrace: | 1327 | case IrInstructionIdErrorReturnTrace: |
| 1323 | ir_print_error_return_trace(irp, (IrInstructionErrorReturnTrace *)instruction); | 1328 | ir_print_error_return_trace(irp, (IrInstructionErrorReturnTrace *)instruction); |
| 1324 | break; | 1329 | break; |
| 1330 | case IrInstructionIdErrorUnion: | ||
| 1331 | ir_print_error_union(irp, (IrInstructionErrorUnion *)instruction); | ||
| 1332 | break; | ||
| 1325 | } | 1333 | } |
| 1326 | fprintf(irp->f, "\n"); | 1334 | fprintf(irp->f, "\n"); |
| 1327 | } | 1335 | } |
src/main.cpp+8| ... | @@ -66,6 +66,7 @@ static int usage(const char *arg0) { | ... | @@ -66,6 +66,7 @@ static int usage(const char *arg0) { |
| 66 | " --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides\n" | 66 | " --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides\n" |
| 67 | " --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides\n" | 67 | " --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides\n" |
| 68 | " --library [lib] link against lib\n" | 68 | " --library [lib] link against lib\n" |
| 69 | " --forbid-library [lib] make it an error to link against lib\n" | ||
| 69 | " --library-path [dir] add a directory to the library search path\n" | 70 | " --library-path [dir] add a directory to the library search path\n" |
| 70 | " --linker-script [path] use a custom linker script\n" | 71 | " --linker-script [path] use a custom linker script\n" |
| 71 | " --object [obj] add object file to build\n" | 72 | " --object [obj] add object file to build\n" |
| ... | @@ -309,6 +310,7 @@ int main(int argc, char **argv) { | ... | @@ -309,6 +310,7 @@ int main(int argc, char **argv) { |
| 309 | ZigList<const char *> llvm_argv = {0}; | 310 | ZigList<const char *> llvm_argv = {0}; |
| 310 | ZigList<const char *> lib_dirs = {0}; | 311 | ZigList<const char *> lib_dirs = {0}; |
| 311 | ZigList<const char *> link_libs = {0}; | 312 | ZigList<const char *> link_libs = {0}; |
| 313 | ZigList<const char *> forbidden_link_libs = {0}; | ||
| 312 | ZigList<const char *> frameworks = {0}; | 314 | ZigList<const char *> frameworks = {0}; |
| 313 | int err; | 315 | int err; |
| 314 | const char *target_arch = nullptr; | 316 | const char *target_arch = nullptr; |
| ... | @@ -605,6 +607,8 @@ int main(int argc, char **argv) { | ... | @@ -605,6 +607,8 @@ int main(int argc, char **argv) { |
| 605 | lib_dirs.append(argv[i]); | 607 | lib_dirs.append(argv[i]); |
| 606 | } else if (strcmp(arg, "--library") == 0) { | 608 | } else if (strcmp(arg, "--library") == 0) { |
| 607 | link_libs.append(argv[i]); | 609 | link_libs.append(argv[i]); |
| 610 | } else if (strcmp(arg, "--forbid-library") == 0) { | ||
| 611 | forbidden_link_libs.append(argv[i]); | ||
| 608 | } else if (strcmp(arg, "--object") == 0) { | 612 | } else if (strcmp(arg, "--object") == 0) { |
| 609 | objects.append(argv[i]); | 613 | objects.append(argv[i]); |
| 610 | } else if (strcmp(arg, "--assembly") == 0) { | 614 | } else if (strcmp(arg, "--assembly") == 0) { |
| ... | @@ -817,6 +821,10 @@ int main(int argc, char **argv) { | ... | @@ -817,6 +821,10 @@ int main(int argc, char **argv) { |
| 817 | LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i))); | 821 | LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i))); |
| 818 | link_lib->provided_explicitly = true; | 822 | link_lib->provided_explicitly = true; |
| 819 | } | 823 | } |
| 824 | for (size_t i = 0; i < forbidden_link_libs.length; i += 1) { | ||
| 825 | Buf *forbidden_link_lib = buf_create_from_str(forbidden_link_libs.at(i)); | ||
| 826 | codegen_add_forbidden_lib(g, forbidden_link_lib); | ||
| 827 | } | ||
| 820 | for (size_t i = 0; i < frameworks.length; i += 1) { | 828 | for (size_t i = 0; i < frameworks.length; i += 1) { |
| 821 | codegen_add_framework(g, frameworks.at(i)); | 829 | codegen_add_framework(g, frameworks.at(i)); |
| 822 | } | 830 | } |
src/parser.cpp+74-42| ... | @@ -221,6 +221,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, size_t *token_index, bo | ... | @@ -221,6 +221,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, size_t *token_index, bo |
| 221 | static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory); | 221 | static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory); |
| 222 | static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory); | 222 | static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory); |
| 223 | static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index); | 223 | static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index); |
| 224 | static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index); | ||
| 224 | 225 | ||
| 225 | static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) { | 226 | static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) { |
| 226 | if (token->id == token_id) { | 227 | if (token->id == token_id) { |
| ... | @@ -240,7 +241,28 @@ static Token *ast_eat_token(ParseContext *pc, size_t *token_index, TokenId token | ... | @@ -240,7 +241,28 @@ static Token *ast_eat_token(ParseContext *pc, size_t *token_index, TokenId token |
| 240 | } | 241 | } |
| 241 | 242 | ||
| 242 | /* | 243 | /* |
| 243 | TypeExpr = PrefixOpExpression | "var" | 244 | ErrorSetExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression |
| 245 | */ | ||
| 246 | static 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 | /* | ||
| 265 | TypeExpr = ErrorSetExpr | "var" | ||
| 244 | */ | 266 | */ |
| 245 | static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool mandatory) { | 267 | static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 246 | Token *token = &pc->tokens->at(*token_index); | 268 | Token *token = &pc->tokens->at(*token_index); |
| ... | @@ -249,7 +271,7 @@ static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool | ... | @@ -249,7 +271,7 @@ static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool |
| 249 | *token_index += 1; | 271 | *token_index += 1; |
| 250 | return node; | 272 | return node; |
| 251 | } else { | 273 | } else { |
| 252 | return ast_parse_prefix_op_expr(pc, token_index, mandatory); | 274 | return ast_parse_error_set_expr(pc, token_index, mandatory); |
| 253 | } | 275 | } |
| 254 | } | 276 | } |
| 255 | 277 | ||
| ... | @@ -651,8 +673,9 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b | ... | @@ -651,8 +673,9 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b |
| 651 | } | 673 | } |
| 652 | 674 | ||
| 653 | /* | 675 | /* |
| 654 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl | ("continue" option(":" Symbol)) | 676 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl |
| 655 | KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | 677 | KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" |
| 678 | ErrorSetDecl = "error" "{" list(Symbol, ",") "}" | ||
| 656 | */ | 679 | */ |
| 657 | static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) { | 680 | static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 658 | Token *token = &pc->tokens->at(*token_index); | 681 | Token *token = &pc->tokens->at(*token_index); |
| ... | @@ -716,9 +739,31 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo | ... | @@ -716,9 +739,31 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo |
| 716 | *token_index += 1; | 739 | *token_index += 1; |
| 717 | return node; | 740 | return node; |
| 718 | } else if (token->id == TokenIdKeywordError) { | 741 | } else if (token->id == TokenIdKeywordError) { |
| 719 | AstNode *node = ast_create_node(pc, NodeTypeErrorType, token); | 742 | Token *next_token = &pc->tokens->at(*token_index + 1); |
| 720 | *token_index += 1; | 743 | if (next_token->id == TokenIdLBrace) { |
| 721 | return node; | 744 | AstNode *node = ast_create_node(pc, NodeTypeErrorSetDecl, token); |
| 745 | *token_index += 2; | ||
| 746 | for (;;) { | ||
| 747 | Token *item_tok = &pc->tokens->at(*token_index); | ||
| 748 | if (item_tok->id == TokenIdRBrace) { | ||
| 749 | *token_index += 1; | ||
| 750 | return node; | ||
| 751 | } else if (item_tok->id == TokenIdSymbol) { | ||
| 752 | AstNode *symbol_node = ast_parse_symbol(pc, token_index); | ||
| 753 | node->data.err_set_decl.decls.append(symbol_node); | ||
| 754 | Token *opt_comma_tok = &pc->tokens->at(*token_index); | ||
| 755 | if (opt_comma_tok->id == TokenIdComma) { | ||
| 756 | *token_index += 1; | ||
| 757 | } | ||
| 758 | } else { | ||
| 759 | ast_invalid_token_error(pc, item_tok); | ||
| 760 | } | ||
| 761 | } | ||
| 762 | } else { | ||
| 763 | AstNode *node = ast_create_node(pc, NodeTypeErrorType, token); | ||
| 764 | *token_index += 1; | ||
| 765 | return node; | ||
| 766 | } | ||
| 722 | } else if (token->id == TokenIdAtSign) { | 767 | } else if (token->id == TokenIdAtSign) { |
| 723 | *token_index += 1; | 768 | *token_index += 1; |
| 724 | Token *name_tok = &pc->tokens->at(*token_index); | 769 | Token *name_tok = &pc->tokens->at(*token_index); |
| ... | @@ -950,7 +995,6 @@ static PrefixOp tok_to_prefix_op(Token *token) { | ... | @@ -950,7 +995,6 @@ static PrefixOp tok_to_prefix_op(Token *token) { |
| 950 | case TokenIdTilde: return PrefixOpBinNot; | 995 | case TokenIdTilde: return PrefixOpBinNot; |
| 951 | case TokenIdStar: return PrefixOpDereference; | 996 | case TokenIdStar: return PrefixOpDereference; |
| 952 | case TokenIdMaybe: return PrefixOpMaybe; | 997 | case TokenIdMaybe: return PrefixOpMaybe; |
| 953 | case TokenIdPercent: return PrefixOpError; | ||
| 954 | case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe; | 998 | case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe; |
| 955 | case TokenIdStarStar: return PrefixOpDereference; | 999 | case TokenIdStarStar: return PrefixOpDereference; |
| 956 | default: return PrefixOpInvalid; | 1000 | default: return PrefixOpInvalid; |
| ... | @@ -997,8 +1041,8 @@ static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) { | ... | @@ -997,8 +1041,8 @@ static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) { |
| 997 | } | 1041 | } |
| 998 | 1042 | ||
| 999 | /* | 1043 | /* |
| 1000 | PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression | 1044 | PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression |
| 1001 | PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%" | "try" | 1045 | PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" |
| 1002 | */ | 1046 | */ |
| 1003 | static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) { | 1047 | static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 1004 | Token *token = &pc->tokens->at(*token_index); | 1048 | Token *token = &pc->tokens->at(*token_index); |
| ... | @@ -1028,7 +1072,7 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, | ... | @@ -1028,7 +1072,7 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, |
| 1028 | node->column += 1; | 1072 | node->column += 1; |
| 1029 | } | 1073 | } |
| 1030 | 1074 | ||
| 1031 | AstNode *prefix_op_expr = ast_parse_prefix_op_expr(pc, token_index, true); | 1075 | AstNode *prefix_op_expr = ast_parse_error_set_expr(pc, token_index, true); |
| 1032 | node->data.prefix_op_expr.primary_expr = prefix_op_expr; | 1076 | node->data.prefix_op_expr.primary_expr = prefix_op_expr; |
| 1033 | node->data.prefix_op_expr.prefix_op = prefix_op; | 1077 | node->data.prefix_op_expr.prefix_op = prefix_op; |
| 1034 | 1078 | ||
| ... | @@ -1043,12 +1087,14 @@ static BinOpType tok_to_mult_op(Token *token) { | ... | @@ -1043,12 +1087,14 @@ static BinOpType tok_to_mult_op(Token *token) { |
| 1043 | case TokenIdStarStar: return BinOpTypeArrayMult; | 1087 | case TokenIdStarStar: return BinOpTypeArrayMult; |
| 1044 | case TokenIdSlash: return BinOpTypeDiv; | 1088 | case TokenIdSlash: return BinOpTypeDiv; |
| 1045 | case TokenIdPercent: return BinOpTypeMod; | 1089 | case TokenIdPercent: return BinOpTypeMod; |
| 1090 | case TokenIdBang: return BinOpTypeErrorUnion; | ||
| 1091 | case TokenIdBarBar: return BinOpTypeMergeErrorSets; | ||
| 1046 | default: return BinOpTypeInvalid; | 1092 | default: return BinOpTypeInvalid; |
| 1047 | } | 1093 | } |
| 1048 | } | 1094 | } |
| 1049 | 1095 | ||
| 1050 | /* | 1096 | /* |
| 1051 | MultiplyOperator = "*" | "/" | "%" | "**" | "*%" | 1097 | MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%" |
| 1052 | */ | 1098 | */ |
| 1053 | static BinOpType ast_parse_mult_op(ParseContext *pc, size_t *token_index, bool mandatory) { | 1099 | static BinOpType ast_parse_mult_op(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 1054 | Token *token = &pc->tokens->at(*token_index); | 1100 | Token *token = &pc->tokens->at(*token_index); |
| ... | @@ -2240,7 +2286,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand | ... | @@ -2240,7 +2286,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand |
| 2240 | } | 2286 | } |
| 2241 | 2287 | ||
| 2242 | /* | 2288 | /* |
| 2243 | FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") TypeExpr | 2289 | FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr |
| 2244 | */ | 2290 | */ |
| 2245 | static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) { | 2291 | static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) { |
| 2246 | Token *first_token = &pc->tokens->at(*token_index); | 2292 | Token *first_token = &pc->tokens->at(*token_index); |
| ... | @@ -2315,6 +2361,18 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m | ... | @@ -2315,6 +2361,18 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m |
| 2315 | ast_eat_token(pc, token_index, TokenIdRParen); | 2361 | ast_eat_token(pc, token_index, TokenIdRParen); |
| 2316 | next_token = &pc->tokens->at(*token_index); | 2362 | next_token = &pc->tokens->at(*token_index); |
| 2317 | } | 2363 | } |
| 2364 | if (next_token->id == TokenIdKeywordError) { | ||
| 2365 | Token *maybe_lbrace_tok = &pc->tokens->at(*token_index + 1); | ||
| 2366 | if (maybe_lbrace_tok->id == TokenIdLBrace) { | ||
| 2367 | *token_index += 1; | ||
| 2368 | node->data.fn_proto.return_type = ast_create_node(pc, NodeTypeErrorType, next_token); | ||
| 2369 | return node; | ||
| 2370 | } | ||
| 2371 | } else if (next_token->id == TokenIdBang) { | ||
| 2372 | *token_index += 1; | ||
| 2373 | node->data.fn_proto.auto_err_set = true; | ||
| 2374 | next_token = &pc->tokens->at(*token_index); | ||
| 2375 | } | ||
| 2318 | node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, true); | 2376 | node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, true); |
| 2319 | 2377 | ||
| 2320 | return node; | 2378 | return node; |
| ... | @@ -2531,7 +2589,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, | ... | @@ -2531,7 +2589,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, |
| 2531 | Token *colon_token = &pc->tokens->at(*token_index); | 2589 | Token *colon_token = &pc->tokens->at(*token_index); |
| 2532 | if (colon_token->id == TokenIdColon) { | 2590 | if (colon_token->id == TokenIdColon) { |
| 2533 | *token_index += 1; | 2591 | *token_index += 1; |
| 2534 | field_node->data.struct_field.type = ast_parse_prefix_op_expr(pc, token_index, true); | 2592 | field_node->data.struct_field.type = ast_parse_type_expr(pc, token_index, true); |
| 2535 | } | 2593 | } |
| 2536 | Token *eq_token = &pc->tokens->at(*token_index); | 2594 | Token *eq_token = &pc->tokens->at(*token_index); |
| 2537 | if (eq_token->id == TokenIdEq) { | 2595 | if (eq_token->id == TokenIdEq) { |
| ... | @@ -2559,26 +2617,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, | ... | @@ -2559,26 +2617,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, |
| 2559 | return node; | 2617 | return node; |
| 2560 | } | 2618 | } |
| 2561 | 2619 | ||
| 2562 | /* | ||
| 2563 | ErrorValueDecl : "error" "Symbol" ";" | ||
| 2564 | */ | ||
| 2565 | static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index) { | ||
| 2566 | Token *first_token = &pc->tokens->at(*token_index); | ||
| 2567 | |||
| 2568 | if (first_token->id != TokenIdKeywordError) { | ||
| 2569 | return nullptr; | ||
| 2570 | } | ||
| 2571 | *token_index += 1; | ||
| 2572 | |||
| 2573 | Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol); | ||
| 2574 | ast_eat_token(pc, token_index, TokenIdSemicolon); | ||
| 2575 | |||
| 2576 | AstNode *node = ast_create_node(pc, NodeTypeErrorValueDecl, first_token); | ||
| 2577 | node->data.error_value_decl.name = token_buf(name_tok); | ||
| 2578 | |||
| 2579 | return node; | ||
| 2580 | } | ||
| 2581 | |||
| 2582 | /* | 2620 | /* |
| 2583 | TestDecl = "test" String Block | 2621 | TestDecl = "test" String Block |
| 2584 | */ | 2622 | */ |
| ... | @@ -2611,12 +2649,6 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig | ... | @@ -2611,12 +2649,6 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig |
| 2611 | continue; | 2649 | continue; |
| 2612 | } | 2650 | } |
| 2613 | 2651 | ||
| 2614 | AstNode *error_value_node = ast_parse_error_value_decl(pc, token_index); | ||
| 2615 | if (error_value_node) { | ||
| 2616 | top_level_decls->append(error_value_node); | ||
| 2617 | continue; | ||
| 2618 | } | ||
| 2619 | |||
| 2620 | AstNode *test_decl_node = ast_parse_test_decl_node(pc, token_index); | 2652 | AstNode *test_decl_node = ast_parse_test_decl_node(pc, token_index); |
| 2621 | if (test_decl_node) { | 2653 | if (test_decl_node) { |
| 2622 | top_level_decls->append(test_decl_node); | 2654 | top_level_decls->append(test_decl_node); |
| ... | @@ -2744,9 +2776,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont | ... | @@ -2744,9 +2776,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 2744 | visit_field(&node->data.variable_declaration.align_expr, visit, context); | 2776 | visit_field(&node->data.variable_declaration.align_expr, visit, context); |
| 2745 | visit_field(&node->data.variable_declaration.section_expr, visit, context); | 2777 | visit_field(&node->data.variable_declaration.section_expr, visit, context); |
| 2746 | break; | 2778 | break; |
| 2747 | case NodeTypeErrorValueDecl: | ||
| 2748 | // none | ||
| 2749 | break; | ||
| 2750 | case NodeTypeTestDecl: | 2779 | case NodeTypeTestDecl: |
| 2751 | visit_field(&node->data.test_decl.body, visit, context); | 2780 | visit_field(&node->data.test_decl.body, visit, context); |
| 2752 | break; | 2781 | break; |
| ... | @@ -2899,5 +2928,8 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont | ... | @@ -2899,5 +2928,8 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 2899 | visit_field(&node->data.addr_of_expr.align_expr, visit, context); | 2928 | visit_field(&node->data.addr_of_expr.align_expr, visit, context); |
| 2900 | visit_field(&node->data.addr_of_expr.op_expr, visit, context); | 2929 | visit_field(&node->data.addr_of_expr.op_expr, visit, context); |
| 2901 | break; | 2930 | break; |
| 2931 | case NodeTypeErrorSetDecl: | ||
| 2932 | visit_node_list(&node->data.err_set_decl.decls, visit, context); | ||
| 2933 | break; | ||
| 2902 | } | 2934 | } |
| 2903 | } | 2935 | } |
src/tokenizer.cpp+25-4| ... | @@ -195,7 +195,8 @@ enum TokenizeState { | ... | @@ -195,7 +195,8 @@ enum TokenizeState { |
| 195 | TokenizeStateSawMinusPercent, | 195 | TokenizeStateSawMinusPercent, |
| 196 | TokenizeStateSawAmpersand, | 196 | TokenizeStateSawAmpersand, |
| 197 | TokenizeStateSawCaret, | 197 | TokenizeStateSawCaret, |
| 198 | TokenizeStateSawPipe, | 198 | TokenizeStateSawBar, |
| 199 | TokenizeStateSawBarBar, | ||
| 199 | TokenizeStateLineComment, | 200 | TokenizeStateLineComment, |
| 200 | TokenizeStateLineString, | 201 | TokenizeStateLineString, |
| 201 | TokenizeStateLineStringEnd, | 202 | TokenizeStateLineStringEnd, |
| ... | @@ -594,7 +595,7 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -594,7 +595,7 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 594 | break; | 595 | break; |
| 595 | case '|': | 596 | case '|': |
| 596 | begin_token(&t, TokenIdBinOr); | 597 | begin_token(&t, TokenIdBinOr); |
| 597 | t.state = TokenizeStateSawPipe; | 598 | t.state = TokenizeStateSawBar; |
| 598 | break; | 599 | break; |
| 599 | case '=': | 600 | case '=': |
| 600 | begin_token(&t, TokenIdEq); | 601 | begin_token(&t, TokenIdEq); |
| ... | @@ -888,13 +889,17 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -888,13 +889,17 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 888 | continue; | 889 | continue; |
| 889 | } | 890 | } |
| 890 | break; | 891 | break; |
| 891 | case TokenizeStateSawPipe: | 892 | case TokenizeStateSawBar: |
| 892 | switch (c) { | 893 | switch (c) { |
| 893 | case '=': | 894 | case '=': |
| 894 | set_token_id(&t, t.cur_tok, TokenIdBitOrEq); | 895 | set_token_id(&t, t.cur_tok, TokenIdBitOrEq); |
| 895 | end_token(&t); | 896 | end_token(&t); |
| 896 | t.state = TokenizeStateStart; | 897 | t.state = TokenizeStateStart; |
| 897 | break; | 898 | break; |
| 899 | case '|': | ||
| 900 | set_token_id(&t, t.cur_tok, TokenIdBarBar); | ||
| 901 | t.state = TokenizeStateSawBarBar; | ||
| 902 | break; | ||
| 898 | default: | 903 | default: |
| 899 | t.pos -= 1; | 904 | t.pos -= 1; |
| 900 | end_token(&t); | 905 | end_token(&t); |
| ... | @@ -902,6 +907,19 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -902,6 +907,19 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 902 | continue; | 907 | continue; |
| 903 | } | 908 | } |
| 904 | break; | 909 | break; |
| 910 | case TokenizeStateSawBarBar: | ||
| 911 | switch (c) { | ||
| 912 | case '=': | ||
| 913 | set_token_id(&t, t.cur_tok, TokenIdBarBarEq); | ||
| 914 | end_token(&t); | ||
| 915 | t.state = TokenizeStateStart; | ||
| 916 | break; | ||
| 917 | default: | ||
| 918 | t.pos -= 1; | ||
| 919 | end_token(&t); | ||
| 920 | t.state = TokenizeStateStart; | ||
| 921 | continue; | ||
| 922 | } | ||
| 905 | case TokenizeStateSawSlash: | 923 | case TokenizeStateSawSlash: |
| 906 | switch (c) { | 924 | switch (c) { |
| 907 | case '/': | 925 | case '/': |
| ... | @@ -1428,7 +1446,7 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -1428,7 +1446,7 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1428 | case TokenizeStateSawDash: | 1446 | case TokenizeStateSawDash: |
| 1429 | case TokenizeStateSawAmpersand: | 1447 | case TokenizeStateSawAmpersand: |
| 1430 | case TokenizeStateSawCaret: | 1448 | case TokenizeStateSawCaret: |
| 1431 | case TokenizeStateSawPipe: | 1449 | case TokenizeStateSawBar: |
| 1432 | case TokenizeStateSawEq: | 1450 | case TokenizeStateSawEq: |
| 1433 | case TokenizeStateSawBang: | 1451 | case TokenizeStateSawBang: |
| 1434 | case TokenizeStateSawLessThan: | 1452 | case TokenizeStateSawLessThan: |
| ... | @@ -1443,6 +1461,7 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -1443,6 +1461,7 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1443 | case TokenizeStateSawMinusPercent: | 1461 | case TokenizeStateSawMinusPercent: |
| 1444 | case TokenizeStateLineString: | 1462 | case TokenizeStateLineString: |
| 1445 | case TokenizeStateLineStringEnd: | 1463 | case TokenizeStateLineStringEnd: |
| 1464 | case TokenizeStateSawBarBar: | ||
| 1446 | end_token(&t); | 1465 | end_token(&t); |
| 1447 | break; | 1466 | break; |
| 1448 | case TokenizeStateSawDotDot: | 1467 | case TokenizeStateSawDotDot: |
| ... | @@ -1475,6 +1494,7 @@ const char * token_name(TokenId id) { | ... | @@ -1475,6 +1494,7 @@ const char * token_name(TokenId id) { |
| 1475 | case TokenIdArrow: return "->"; | 1494 | case TokenIdArrow: return "->"; |
| 1476 | case TokenIdAtSign: return "@"; | 1495 | case TokenIdAtSign: return "@"; |
| 1477 | case TokenIdBang: return "!"; | 1496 | case TokenIdBang: return "!"; |
| 1497 | case TokenIdBarBar: return "||"; | ||
| 1478 | case TokenIdBinOr: return "|"; | 1498 | case TokenIdBinOr: return "|"; |
| 1479 | case TokenIdBinXor: return "^"; | 1499 | case TokenIdBinXor: return "^"; |
| 1480 | case TokenIdBitAndEq: return "&="; | 1500 | case TokenIdBitAndEq: return "&="; |
| ... | @@ -1577,6 +1597,7 @@ const char * token_name(TokenId id) { | ... | @@ -1577,6 +1597,7 @@ const char * token_name(TokenId id) { |
| 1577 | case TokenIdTimesEq: return "*="; | 1597 | case TokenIdTimesEq: return "*="; |
| 1578 | case TokenIdTimesPercent: return "*%"; | 1598 | case TokenIdTimesPercent: return "*%"; |
| 1579 | case TokenIdTimesPercentEq: return "*%="; | 1599 | case TokenIdTimesPercentEq: return "*%="; |
| 1600 | case TokenIdBarBarEq: return "||="; | ||
| 1580 | } | 1601 | } |
| 1581 | return "(invalid token)"; | 1602 | return "(invalid token)"; |
| 1582 | } | 1603 | } |
src/tokenizer.hpp+2| ... | @@ -17,6 +17,8 @@ enum TokenId { | ... | @@ -17,6 +17,8 @@ enum TokenId { |
| 17 | TokenIdArrow, | 17 | TokenIdArrow, |
| 18 | TokenIdAtSign, | 18 | TokenIdAtSign, |
| 19 | TokenIdBang, | 19 | TokenIdBang, |
| 20 | TokenIdBarBar, | ||
| 21 | TokenIdBarBarEq, | ||
| 20 | TokenIdBinOr, | 22 | TokenIdBinOr, |
| 21 | TokenIdBinXor, | 23 | TokenIdBinXor, |
| 22 | TokenIdBitAndEq, | 24 | TokenIdBitAndEq, |
src/util.hpp+11-8| ... | @@ -92,19 +92,22 @@ static inline void safe_memcpy(T *dest, const T *src, size_t count) { | ... | @@ -92,19 +92,22 @@ static inline void safe_memcpy(T *dest, const T *src, size_t count) { |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | template<typename T> | 94 | template<typename T> |
| 95 | static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) { | 95 | static inline T *reallocate(T *old, size_t old_count, size_t new_count) { |
| 96 | #ifdef NDEBUG | ||
| 97 | T *ptr = reinterpret_cast<T*>(realloc(old, new_count * sizeof(T))); | 96 | T *ptr = reinterpret_cast<T*>(realloc(old, new_count * sizeof(T))); |
| 98 | if (!ptr) | 97 | if (!ptr) |
| 99 | zig_panic("allocation failed"); | 98 | zig_panic("allocation failed"); |
| 99 | if (new_count > old_count) { | ||
| 100 | memset(&ptr[old_count], 0, (new_count - old_count) * sizeof(T)); | ||
| 101 | } | ||
| 100 | return ptr; | 102 | return ptr; |
| 101 | #else | 103 | } |
| 102 | // manually assign every element to trigger compile error for non-copyable structs | 104 | |
| 103 | T *ptr = allocate_nonzero<T>(new_count); | 105 | template<typename T> |
| 104 | safe_memcpy(ptr, old, old_count); | 106 | static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) { |
| 105 | free(old); | 107 | T *ptr = reinterpret_cast<T*>(realloc(old, new_count * sizeof(T))); |
| 108 | if (!ptr) | ||
| 109 | zig_panic("allocation failed"); | ||
| 106 | return ptr; | 110 | return ptr; |
| 107 | #endif | ||
| 108 | } | 111 | } |
| 109 | 112 | ||
| 110 | template <typename T, size_t n> | 113 | template <typename T, size_t n> |
src/zig_llvm.cpp+4| ... | @@ -437,6 +437,10 @@ unsigned ZigLLVMTag_DW_structure_type(void) { | ... | @@ -437,6 +437,10 @@ unsigned ZigLLVMTag_DW_structure_type(void) { |
| 437 | return dwarf::DW_TAG_structure_type; | 437 | return dwarf::DW_TAG_structure_type; |
| 438 | } | 438 | } |
| 439 | 439 | ||
| 440 | unsigned ZigLLVMTag_DW_enumeration_type(void) { | ||
| 441 | return dwarf::DW_TAG_enumeration_type; | ||
| 442 | } | ||
| 443 | |||
| 440 | unsigned ZigLLVMTag_DW_union_type(void) { | 444 | unsigned ZigLLVMTag_DW_union_type(void) { |
| 441 | return dwarf::DW_TAG_union_type; | 445 | return dwarf::DW_TAG_union_type; |
| 442 | } | 446 | } |
src/zig_llvm.h+1| ... | @@ -133,6 +133,7 @@ ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_signed_char(void); | ... | @@ -133,6 +133,7 @@ ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_signed_char(void); |
| 133 | ZIG_EXTERN_C unsigned ZigLLVMLang_DW_LANG_C99(void); | 133 | ZIG_EXTERN_C unsigned ZigLLVMLang_DW_LANG_C99(void); |
| 134 | ZIG_EXTERN_C unsigned ZigLLVMTag_DW_variable(void); | 134 | ZIG_EXTERN_C unsigned ZigLLVMTag_DW_variable(void); |
| 135 | ZIG_EXTERN_C unsigned ZigLLVMTag_DW_structure_type(void); | 135 | ZIG_EXTERN_C unsigned ZigLLVMTag_DW_structure_type(void); |
| 136 | ZIG_EXTERN_C unsigned ZigLLVMTag_DW_enumeration_type(void); | ||
| 136 | ZIG_EXTERN_C unsigned ZigLLVMTag_DW_union_type(void); | 137 | ZIG_EXTERN_C unsigned ZigLLVMTag_DW_union_type(void); |
| 137 | 138 | ||
| 138 | ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved); | 139 | ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved); |
std/array_list.zig+7-7| ... | @@ -63,7 +63,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{ | ... | @@ -63,7 +63,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{ |
| 63 | return result; | 63 | return result; |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | pub fn insert(l: &Self, n: usize, item: &const T) %void { | 66 | pub fn insert(l: &Self, n: usize, item: &const T) !void { |
| 67 | try l.ensureCapacity(l.len + 1); | 67 | try l.ensureCapacity(l.len + 1); |
| 68 | l.len += 1; | 68 | l.len += 1; |
| 69 | 69 | ||
| ... | @@ -71,7 +71,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{ | ... | @@ -71,7 +71,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{ |
| 71 | l.items[n] = *item; | 71 | l.items[n] = *item; |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | pub fn insertSlice(l: &Self, n: usize, items: []align(A) const T) %void { | 74 | pub fn insertSlice(l: &Self, n: usize, items: []align(A) const T) !void { |
| 75 | try l.ensureCapacity(l.len + items.len); | 75 | try l.ensureCapacity(l.len + items.len); |
| 76 | l.len += items.len; | 76 | l.len += items.len; |
| 77 | 77 | ||
| ... | @@ -79,18 +79,18 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{ | ... | @@ -79,18 +79,18 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{ |
| 79 | mem.copy(T, l.items[n..n+items.len], items); | 79 | mem.copy(T, l.items[n..n+items.len], items); |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | pub fn append(l: &Self, item: &const T) %void { | 82 | pub fn append(l: &Self, item: &const T) !void { |
| 83 | const new_item_ptr = try l.addOne(); | 83 | const new_item_ptr = try l.addOne(); |
| 84 | *new_item_ptr = *item; | 84 | *new_item_ptr = *item; |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | pub fn appendSlice(l: &Self, items: []align(A) const T) %void { | 87 | pub fn appendSlice(l: &Self, items: []align(A) const T) !void { |
| 88 | try l.ensureCapacity(l.len + items.len); | 88 | try l.ensureCapacity(l.len + items.len); |
| 89 | mem.copy(T, l.items[l.len..], items); | 89 | mem.copy(T, l.items[l.len..], items); |
| 90 | l.len += items.len; | 90 | l.len += items.len; |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | pub fn resize(l: &Self, new_len: usize) %void { | 93 | pub fn resize(l: &Self, new_len: usize) !void { |
| 94 | try l.ensureCapacity(new_len); | 94 | try l.ensureCapacity(new_len); |
| 95 | l.len = new_len; | 95 | l.len = new_len; |
| 96 | } | 96 | } |
| ... | @@ -100,7 +100,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{ | ... | @@ -100,7 +100,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{ |
| 100 | l.len = new_len; | 100 | l.len = new_len; |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | pub fn ensureCapacity(l: &Self, new_capacity: usize) %void { | 103 | pub fn ensureCapacity(l: &Self, new_capacity: usize) !void { |
| 104 | var better_capacity = l.items.len; | 104 | var better_capacity = l.items.len; |
| 105 | if (better_capacity >= new_capacity) return; | 105 | if (better_capacity >= new_capacity) return; |
| 106 | while (true) { | 106 | while (true) { |
| ... | @@ -110,7 +110,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{ | ... | @@ -110,7 +110,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{ |
| 110 | l.items = try l.allocator.alignedRealloc(T, A, l.items, better_capacity); | 110 | l.items = try l.allocator.alignedRealloc(T, A, l.items, better_capacity); |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | pub fn addOne(l: &Self) %&T { | 113 | pub fn addOne(l: &Self) !&T { |
| 114 | const new_length = l.len + 1; | 114 | const new_length = l.len + 1; |
| 115 | try l.ensureCapacity(new_length); | 115 | try l.ensureCapacity(new_length); |
| 116 | const result = &l.items[l.len]; | 116 | const result = &l.items[l.len]; |
std/base64.zig+11-16| ... | @@ -79,8 +79,6 @@ pub const Base64Encoder = struct { | ... | @@ -79,8 +79,6 @@ pub const Base64Encoder = struct { |
| 79 | }; | 79 | }; |
| 80 | 80 | ||
| 81 | pub const standard_decoder = Base64Decoder.init(standard_alphabet_chars, standard_pad_char); | 81 | pub const standard_decoder = Base64Decoder.init(standard_alphabet_chars, standard_pad_char); |
| 82 | error InvalidPadding; | ||
| 83 | error InvalidCharacter; | ||
| 84 | 82 | ||
| 85 | pub const Base64Decoder = struct { | 83 | pub const Base64Decoder = struct { |
| 86 | /// e.g. 'A' => 0. | 84 | /// e.g. 'A' => 0. |
| ... | @@ -111,7 +109,7 @@ pub const Base64Decoder = struct { | ... | @@ -111,7 +109,7 @@ pub const Base64Decoder = struct { |
| 111 | } | 109 | } |
| 112 | 110 | ||
| 113 | /// If the encoded buffer is detected to be invalid, returns error.InvalidPadding. | 111 | /// If the encoded buffer is detected to be invalid, returns error.InvalidPadding. |
| 114 | pub fn calcSize(decoder: &const Base64Decoder, source: []const u8) %usize { | 112 | pub fn calcSize(decoder: &const Base64Decoder, source: []const u8) !usize { |
| 115 | if (source.len % 4 != 0) return error.InvalidPadding; | 113 | if (source.len % 4 != 0) return error.InvalidPadding; |
| 116 | return calcDecodedSizeExactUnsafe(source, decoder.pad_char); | 114 | return calcDecodedSizeExactUnsafe(source, decoder.pad_char); |
| 117 | } | 115 | } |
| ... | @@ -119,7 +117,7 @@ pub const Base64Decoder = struct { | ... | @@ -119,7 +117,7 @@ pub const Base64Decoder = struct { |
| 119 | /// dest.len must be what you get from ::calcSize. | 117 | /// dest.len must be what you get from ::calcSize. |
| 120 | /// invalid characters result in error.InvalidCharacter. | 118 | /// invalid characters result in error.InvalidCharacter. |
| 121 | /// invalid padding results in error.InvalidPadding. | 119 | /// invalid padding results in error.InvalidPadding. |
| 122 | pub fn decode(decoder: &const Base64Decoder, dest: []u8, source: []const u8) %void { | 120 | pub fn decode(decoder: &const Base64Decoder, dest: []u8, source: []const u8) !void { |
| 123 | assert(dest.len == (decoder.calcSize(source) catch unreachable)); | 121 | assert(dest.len == (decoder.calcSize(source) catch unreachable)); |
| 124 | assert(source.len % 4 == 0); | 122 | assert(source.len % 4 == 0); |
| 125 | 123 | ||
| ... | @@ -163,8 +161,6 @@ pub const Base64Decoder = struct { | ... | @@ -163,8 +161,6 @@ pub const Base64Decoder = struct { |
| 163 | } | 161 | } |
| 164 | }; | 162 | }; |
| 165 | 163 | ||
| 166 | error OutputTooSmall; | ||
| 167 | |||
| 168 | pub const Base64DecoderWithIgnore = struct { | 164 | pub const Base64DecoderWithIgnore = struct { |
| 169 | decoder: Base64Decoder, | 165 | decoder: Base64Decoder, |
| 170 | char_is_ignored: [256]bool, | 166 | char_is_ignored: [256]bool, |
| ... | @@ -185,7 +181,7 @@ pub const Base64DecoderWithIgnore = struct { | ... | @@ -185,7 +181,7 @@ pub const Base64DecoderWithIgnore = struct { |
| 185 | } | 181 | } |
| 186 | 182 | ||
| 187 | /// If no characters end up being ignored or padding, this will be the exact decoded size. | 183 | /// If no characters end up being ignored or padding, this will be the exact decoded size. |
| 188 | pub fn calcSizeUpperBound(encoded_len: usize) %usize { | 184 | pub fn calcSizeUpperBound(encoded_len: usize) usize { |
| 189 | return @divTrunc(encoded_len, 4) * 3; | 185 | return @divTrunc(encoded_len, 4) * 3; |
| 190 | } | 186 | } |
| 191 | 187 | ||
| ... | @@ -193,7 +189,7 @@ pub const Base64DecoderWithIgnore = struct { | ... | @@ -193,7 +189,7 @@ pub const Base64DecoderWithIgnore = struct { |
| 193 | /// Invalid padding results in error.InvalidPadding. | 189 | /// Invalid padding results in error.InvalidPadding. |
| 194 | /// Decoding more data than can fit in dest results in error.OutputTooSmall. See also ::calcSizeUpperBound. | 190 | /// Decoding more data than can fit in dest results in error.OutputTooSmall. See also ::calcSizeUpperBound. |
| 195 | /// Returns the number of bytes writen to dest. | 191 | /// Returns the number of bytes writen to dest. |
| 196 | pub fn decode(decoder_with_ignore: &const Base64DecoderWithIgnore, dest: []u8, source: []const u8) %usize { | 192 | pub fn decode(decoder_with_ignore: &const Base64DecoderWithIgnore, dest: []u8, source: []const u8) !usize { |
| 197 | const decoder = &decoder_with_ignore.decoder; | 193 | const decoder = &decoder_with_ignore.decoder; |
| 198 | 194 | ||
| 199 | var src_cursor: usize = 0; | 195 | var src_cursor: usize = 0; |
| ... | @@ -378,7 +374,7 @@ test "base64" { | ... | @@ -378,7 +374,7 @@ test "base64" { |
| 378 | comptime (testBase64() catch unreachable); | 374 | comptime (testBase64() catch unreachable); |
| 379 | } | 375 | } |
| 380 | 376 | ||
| 381 | fn testBase64() %void { | 377 | fn testBase64() !void { |
| 382 | try testAllApis("", ""); | 378 | try testAllApis("", ""); |
| 383 | try testAllApis("f", "Zg=="); | 379 | try testAllApis("f", "Zg=="); |
| 384 | try testAllApis("fo", "Zm8="); | 380 | try testAllApis("fo", "Zm8="); |
| ... | @@ -412,7 +408,7 @@ fn testBase64() %void { | ... | @@ -412,7 +408,7 @@ fn testBase64() %void { |
| 412 | try testOutputTooSmallError("AAAAAA=="); | 408 | try testOutputTooSmallError("AAAAAA=="); |
| 413 | } | 409 | } |
| 414 | 410 | ||
| 415 | fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) %void { | 411 | fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void { |
| 416 | // Base64Encoder | 412 | // Base64Encoder |
| 417 | { | 413 | { |
| 418 | var buffer: [0x100]u8 = undefined; | 414 | var buffer: [0x100]u8 = undefined; |
| ... | @@ -434,7 +430,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) %void | ... | @@ -434,7 +430,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) %void |
| 434 | const standard_decoder_ignore_nothing = Base64DecoderWithIgnore.init( | 430 | const standard_decoder_ignore_nothing = Base64DecoderWithIgnore.init( |
| 435 | standard_alphabet_chars, standard_pad_char, ""); | 431 | standard_alphabet_chars, standard_pad_char, ""); |
| 436 | var buffer: [0x100]u8 = undefined; | 432 | var buffer: [0x100]u8 = undefined; |
| 437 | var decoded = buffer[0..try Base64DecoderWithIgnore.calcSizeUpperBound(expected_encoded.len)]; | 433 | var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(expected_encoded.len)]; |
| 438 | var written = try standard_decoder_ignore_nothing.decode(decoded, expected_encoded); | 434 | var written = try standard_decoder_ignore_nothing.decode(decoded, expected_encoded); |
| 439 | assert(written <= decoded.len); | 435 | assert(written <= decoded.len); |
| 440 | assert(mem.eql(u8, decoded[0..written], expected_decoded)); | 436 | assert(mem.eql(u8, decoded[0..written], expected_decoded)); |
| ... | @@ -449,17 +445,16 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) %void | ... | @@ -449,17 +445,16 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) %void |
| 449 | } | 445 | } |
| 450 | } | 446 | } |
| 451 | 447 | ||
| 452 | fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) %void { | 448 | fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) !void { |
| 453 | const standard_decoder_ignore_space = Base64DecoderWithIgnore.init( | 449 | const standard_decoder_ignore_space = Base64DecoderWithIgnore.init( |
| 454 | standard_alphabet_chars, standard_pad_char, " "); | 450 | standard_alphabet_chars, standard_pad_char, " "); |
| 455 | var buffer: [0x100]u8 = undefined; | 451 | var buffer: [0x100]u8 = undefined; |
| 456 | var decoded = buffer[0..try Base64DecoderWithIgnore.calcSizeUpperBound(encoded.len)]; | 452 | var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(encoded.len)]; |
| 457 | var written = try standard_decoder_ignore_space.decode(decoded, encoded); | 453 | var written = try standard_decoder_ignore_space.decode(decoded, encoded); |
| 458 | assert(mem.eql(u8, decoded[0..written], expected_decoded)); | 454 | assert(mem.eql(u8, decoded[0..written], expected_decoded)); |
| 459 | } | 455 | } |
| 460 | 456 | ||
| 461 | error ExpectedError; | 457 | fn testError(encoded: []const u8, expected_err: error) !void { |
| 462 | fn testError(encoded: []const u8, expected_err: error) %void { | ||
| 463 | const standard_decoder_ignore_space = Base64DecoderWithIgnore.init( | 458 | const standard_decoder_ignore_space = Base64DecoderWithIgnore.init( |
| 464 | standard_alphabet_chars, standard_pad_char, " "); | 459 | standard_alphabet_chars, standard_pad_char, " "); |
| 465 | var buffer: [0x100]u8 = undefined; | 460 | var buffer: [0x100]u8 = undefined; |
| ... | @@ -475,7 +470,7 @@ fn testError(encoded: []const u8, expected_err: error) %void { | ... | @@ -475,7 +470,7 @@ fn testError(encoded: []const u8, expected_err: error) %void { |
| 475 | } else |err| if (err != expected_err) return err; | 470 | } else |err| if (err != expected_err) return err; |
| 476 | } | 471 | } |
| 477 | 472 | ||
| 478 | fn testOutputTooSmallError(encoded: []const u8) %void { | 473 | fn testOutputTooSmallError(encoded: []const u8) !void { |
| 479 | const standard_decoder_ignore_space = Base64DecoderWithIgnore.init( | 474 | const standard_decoder_ignore_space = Base64DecoderWithIgnore.init( |
| 480 | standard_alphabet_chars, standard_pad_char, " "); | 475 | standard_alphabet_chars, standard_pad_char, " "); |
| 481 | var buffer: [0x100]u8 = undefined; | 476 | var buffer: [0x100]u8 = undefined; |
std/buf_map.zig+2-2| ... | @@ -27,7 +27,7 @@ pub const BufMap = struct { | ... | @@ -27,7 +27,7 @@ pub const BufMap = struct { |
| 27 | self.hash_map.deinit(); | 27 | self.hash_map.deinit(); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | pub fn set(self: &BufMap, key: []const u8, value: []const u8) %void { | 30 | pub fn set(self: &BufMap, key: []const u8, value: []const u8) !void { |
| 31 | if (self.hash_map.get(key)) |entry| { | 31 | if (self.hash_map.get(key)) |entry| { |
| 32 | const value_copy = try self.copy(value); | 32 | const value_copy = try self.copy(value); |
| 33 | errdefer self.free(value_copy); | 33 | errdefer self.free(value_copy); |
| ... | @@ -67,7 +67,7 @@ pub const BufMap = struct { | ... | @@ -67,7 +67,7 @@ pub const BufMap = struct { |
| 67 | self.hash_map.allocator.free(mut_value); | 67 | self.hash_map.allocator.free(mut_value); |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | fn copy(self: &BufMap, value: []const u8) %[]const u8 { | 70 | fn copy(self: &BufMap, value: []const u8) ![]const u8 { |
| 71 | const result = try self.hash_map.allocator.alloc(u8, value.len); | 71 | const result = try self.hash_map.allocator.alloc(u8, value.len); |
| 72 | mem.copy(u8, result, value); | 72 | mem.copy(u8, result, value); |
| 73 | return result; | 73 | return result; |
std/buf_set.zig+2-2| ... | @@ -24,7 +24,7 @@ pub const BufSet = struct { | ... | @@ -24,7 +24,7 @@ pub const BufSet = struct { |
| 24 | self.hash_map.deinit(); | 24 | self.hash_map.deinit(); |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | pub fn put(self: &BufSet, key: []const u8) %void { | 27 | pub fn put(self: &BufSet, key: []const u8) !void { |
| 28 | if (self.hash_map.get(key) == null) { | 28 | if (self.hash_map.get(key) == null) { |
| 29 | const key_copy = try self.copy(key); | 29 | const key_copy = try self.copy(key); |
| 30 | errdefer self.free(key_copy); | 30 | errdefer self.free(key_copy); |
| ... | @@ -55,7 +55,7 @@ pub const BufSet = struct { | ... | @@ -55,7 +55,7 @@ pub const BufSet = struct { |
| 55 | self.hash_map.allocator.free(mut_value); | 55 | self.hash_map.allocator.free(mut_value); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | fn copy(self: &BufSet, value: []const u8) %[]const u8 { | 58 | fn copy(self: &BufSet, value: []const u8) ![]const u8 { |
| 59 | const result = try self.hash_map.allocator.alloc(u8, value.len); | 59 | const result = try self.hash_map.allocator.alloc(u8, value.len); |
| 60 | mem.copy(u8, result, value); | 60 | mem.copy(u8, result, value); |
| 61 | return result; | 61 | return result; |
std/buffer.zig+9-9| ... | @@ -12,14 +12,14 @@ pub const Buffer = struct { | ... | @@ -12,14 +12,14 @@ pub const Buffer = struct { |
| 12 | list: ArrayList(u8), | 12 | list: ArrayList(u8), |
| 13 | 13 | ||
| 14 | /// Must deinitialize with deinit. | 14 | /// Must deinitialize with deinit. |
| 15 | pub fn init(allocator: &Allocator, m: []const u8) %Buffer { | 15 | pub fn init(allocator: &Allocator, m: []const u8) !Buffer { |
| 16 | var self = try initSize(allocator, m.len); | 16 | var self = try initSize(allocator, m.len); |
| 17 | mem.copy(u8, self.list.items, m); | 17 | mem.copy(u8, self.list.items, m); |
| 18 | return self; | 18 | return self; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | /// Must deinitialize with deinit. | 21 | /// Must deinitialize with deinit. |
| 22 | pub fn initSize(allocator: &Allocator, size: usize) %Buffer { | 22 | pub fn initSize(allocator: &Allocator, size: usize) !Buffer { |
| 23 | var self = initNull(allocator); | 23 | var self = initNull(allocator); |
| 24 | try self.resize(size); | 24 | try self.resize(size); |
| 25 | return self; | 25 | return self; |
| ... | @@ -37,7 +37,7 @@ pub const Buffer = struct { | ... | @@ -37,7 +37,7 @@ pub const Buffer = struct { |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | /// Must deinitialize with deinit. | 39 | /// Must deinitialize with deinit. |
| 40 | pub fn initFromBuffer(buffer: &const Buffer) %Buffer { | 40 | pub fn initFromBuffer(buffer: &const Buffer) !Buffer { |
| 41 | return Buffer.init(buffer.list.allocator, buffer.toSliceConst()); | 41 | return Buffer.init(buffer.list.allocator, buffer.toSliceConst()); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| ... | @@ -80,7 +80,7 @@ pub const Buffer = struct { | ... | @@ -80,7 +80,7 @@ pub const Buffer = struct { |
| 80 | self.list.items[self.len()] = 0; | 80 | self.list.items[self.len()] = 0; |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | pub fn resize(self: &Buffer, new_len: usize) %void { | 83 | pub fn resize(self: &Buffer, new_len: usize) !void { |
| 84 | try self.list.resize(new_len + 1); | 84 | try self.list.resize(new_len + 1); |
| 85 | self.list.items[self.len()] = 0; | 85 | self.list.items[self.len()] = 0; |
| 86 | } | 86 | } |
| ... | @@ -93,24 +93,24 @@ pub const Buffer = struct { | ... | @@ -93,24 +93,24 @@ pub const Buffer = struct { |
| 93 | return self.list.len - 1; | 93 | return self.list.len - 1; |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | pub fn append(self: &Buffer, m: []const u8) %void { | 96 | pub fn append(self: &Buffer, m: []const u8) !void { |
| 97 | const old_len = self.len(); | 97 | const old_len = self.len(); |
| 98 | try self.resize(old_len + m.len); | 98 | try self.resize(old_len + m.len); |
| 99 | mem.copy(u8, self.list.toSlice()[old_len..], m); | 99 | mem.copy(u8, self.list.toSlice()[old_len..], m); |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | // TODO: remove, use OutStream for this | 102 | // TODO: remove, use OutStream for this |
| 103 | pub fn appendFormat(self: &Buffer, comptime format: []const u8, args: ...) %void { | 103 | pub fn appendFormat(self: &Buffer, comptime format: []const u8, args: ...) !void { |
| 104 | return fmt.format(self, append, format, args); | 104 | return fmt.format(self, append, format, args); |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | // TODO: remove, use OutStream for this | 107 | // TODO: remove, use OutStream for this |
| 108 | pub fn appendByte(self: &Buffer, byte: u8) %void { | 108 | pub fn appendByte(self: &Buffer, byte: u8) !void { |
| 109 | return self.appendByteNTimes(byte, 1); | 109 | return self.appendByteNTimes(byte, 1); |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | // TODO: remove, use OutStream for this | 112 | // TODO: remove, use OutStream for this |
| 113 | pub fn appendByteNTimes(self: &Buffer, byte: u8, count: usize) %void { | 113 | pub fn appendByteNTimes(self: &Buffer, byte: u8, count: usize) !void { |
| 114 | var prev_size: usize = self.len(); | 114 | var prev_size: usize = self.len(); |
| 115 | const new_size = prev_size + count; | 115 | const new_size = prev_size + count; |
| 116 | try self.resize(new_size); | 116 | try self.resize(new_size); |
| ... | @@ -137,7 +137,7 @@ pub const Buffer = struct { | ... | @@ -137,7 +137,7 @@ pub const Buffer = struct { |
| 137 | return mem.eql(u8, self.list.items[start..l], m); | 137 | return mem.eql(u8, self.list.items[start..l], m); |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | pub fn replaceContents(self: &const Buffer, m: []const u8) %void { | 140 | pub fn replaceContents(self: &const Buffer, m: []const u8) !void { |
| 141 | try self.resize(m.len); | 141 | try self.resize(m.len); |
| 142 | mem.copy(u8, self.list.toSlice(), m); | 142 | mem.copy(u8, self.list.toSlice(), m); |
| 143 | } | 143 | } |
std/build.zig+26-33| ... | @@ -15,13 +15,6 @@ const BufSet = std.BufSet; | ... | @@ -15,13 +15,6 @@ const BufSet = std.BufSet; |
| 15 | const BufMap = std.BufMap; | 15 | const BufMap = std.BufMap; |
| 16 | const fmt_lib = std.fmt; | 16 | const fmt_lib = std.fmt; |
| 17 | 17 | ||
| 18 | error ExtraArg; | ||
| 19 | error UncleanExit; | ||
| 20 | error InvalidStepName; | ||
| 21 | error DependencyLoopDetected; | ||
| 22 | error NoCompilerFound; | ||
| 23 | error NeedAnObject; | ||
| 24 | |||
| 25 | pub const Builder = struct { | 18 | pub const Builder = struct { |
| 26 | uninstall_tls: TopLevelStep, | 19 | uninstall_tls: TopLevelStep, |
| 27 | install_tls: TopLevelStep, | 20 | install_tls: TopLevelStep, |
| ... | @@ -242,7 +235,7 @@ pub const Builder = struct { | ... | @@ -242,7 +235,7 @@ pub const Builder = struct { |
| 242 | self.lib_paths.append(path) catch unreachable; | 235 | self.lib_paths.append(path) catch unreachable; |
| 243 | } | 236 | } |
| 244 | 237 | ||
| 245 | pub fn make(self: &Builder, step_names: []const []const u8) %void { | 238 | pub fn make(self: &Builder, step_names: []const []const u8) !void { |
| 246 | var wanted_steps = ArrayList(&Step).init(self.allocator); | 239 | var wanted_steps = ArrayList(&Step).init(self.allocator); |
| 247 | defer wanted_steps.deinit(); | 240 | defer wanted_steps.deinit(); |
| 248 | 241 | ||
| ... | @@ -278,7 +271,7 @@ pub const Builder = struct { | ... | @@ -278,7 +271,7 @@ pub const Builder = struct { |
| 278 | return &self.uninstall_tls.step; | 271 | return &self.uninstall_tls.step; |
| 279 | } | 272 | } |
| 280 | 273 | ||
| 281 | fn makeUninstall(uninstall_step: &Step) %void { | 274 | fn makeUninstall(uninstall_step: &Step) error!void { |
| 282 | const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step); | 275 | const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step); |
| 283 | const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls); | 276 | const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls); |
| 284 | 277 | ||
| ... | @@ -292,7 +285,7 @@ pub const Builder = struct { | ... | @@ -292,7 +285,7 @@ pub const Builder = struct { |
| 292 | // TODO remove empty directories | 285 | // TODO remove empty directories |
| 293 | } | 286 | } |
| 294 | 287 | ||
| 295 | fn makeOneStep(self: &Builder, s: &Step) %void { | 288 | fn makeOneStep(self: &Builder, s: &Step) error!void { |
| 296 | if (s.loop_flag) { | 289 | if (s.loop_flag) { |
| 297 | warn("Dependency loop detected:\n {}\n", s.name); | 290 | warn("Dependency loop detected:\n {}\n", s.name); |
| 298 | return error.DependencyLoopDetected; | 291 | return error.DependencyLoopDetected; |
| ... | @@ -313,7 +306,7 @@ pub const Builder = struct { | ... | @@ -313,7 +306,7 @@ pub const Builder = struct { |
| 313 | try s.make(); | 306 | try s.make(); |
| 314 | } | 307 | } |
| 315 | 308 | ||
| 316 | fn getTopLevelStepByName(self: &Builder, name: []const u8) %&Step { | 309 | fn getTopLevelStepByName(self: &Builder, name: []const u8) !&Step { |
| 317 | for (self.top_level_steps.toSliceConst()) |top_level_step| { | 310 | for (self.top_level_steps.toSliceConst()) |top_level_step| { |
| 318 | if (mem.eql(u8, top_level_step.step.name, name)) { | 311 | if (mem.eql(u8, top_level_step.step.name, name)) { |
| 319 | return &top_level_step.step; | 312 | return &top_level_step.step; |
| ... | @@ -548,7 +541,7 @@ pub const Builder = struct { | ... | @@ -548,7 +541,7 @@ pub const Builder = struct { |
| 548 | return self.invalid_user_input; | 541 | return self.invalid_user_input; |
| 549 | } | 542 | } |
| 550 | 543 | ||
| 551 | fn spawnChild(self: &Builder, argv: []const []const u8) %void { | 544 | fn spawnChild(self: &Builder, argv: []const []const u8) !void { |
| 552 | return self.spawnChildEnvMap(null, &self.env_map, argv); | 545 | return self.spawnChildEnvMap(null, &self.env_map, argv); |
| 553 | } | 546 | } |
| 554 | 547 | ||
| ... | @@ -561,7 +554,7 @@ pub const Builder = struct { | ... | @@ -561,7 +554,7 @@ pub const Builder = struct { |
| 561 | } | 554 | } |
| 562 | 555 | ||
| 563 | fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, | 556 | fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, |
| 564 | argv: []const []const u8) %void | 557 | argv: []const []const u8) !void |
| 565 | { | 558 | { |
| 566 | if (self.verbose) { | 559 | if (self.verbose) { |
| 567 | printCmd(cwd, argv); | 560 | printCmd(cwd, argv); |
| ... | @@ -595,7 +588,7 @@ pub const Builder = struct { | ... | @@ -595,7 +588,7 @@ pub const Builder = struct { |
| 595 | } | 588 | } |
| 596 | } | 589 | } |
| 597 | 590 | ||
| 598 | pub fn makePath(self: &Builder, path: []const u8) %void { | 591 | pub fn makePath(self: &Builder, path: []const u8) !void { |
| 599 | os.makePath(self.allocator, self.pathFromRoot(path)) catch |err| { | 592 | os.makePath(self.allocator, self.pathFromRoot(path)) catch |err| { |
| 600 | warn("Unable to create path {}: {}\n", path, @errorName(err)); | 593 | warn("Unable to create path {}: {}\n", path, @errorName(err)); |
| 601 | return err; | 594 | return err; |
| ... | @@ -630,11 +623,11 @@ pub const Builder = struct { | ... | @@ -630,11 +623,11 @@ pub const Builder = struct { |
| 630 | self.installed_files.append(full_path) catch unreachable; | 623 | self.installed_files.append(full_path) catch unreachable; |
| 631 | } | 624 | } |
| 632 | 625 | ||
| 633 | fn copyFile(self: &Builder, source_path: []const u8, dest_path: []const u8) %void { | 626 | fn copyFile(self: &Builder, source_path: []const u8, dest_path: []const u8) !void { |
| 634 | return self.copyFileMode(source_path, dest_path, 0o666); | 627 | return self.copyFileMode(source_path, dest_path, 0o666); |
| 635 | } | 628 | } |
| 636 | 629 | ||
| 637 | fn copyFileMode(self: &Builder, source_path: []const u8, dest_path: []const u8, mode: usize) %void { | 630 | fn copyFileMode(self: &Builder, source_path: []const u8, dest_path: []const u8, mode: usize) !void { |
| 638 | if (self.verbose) { | 631 | if (self.verbose) { |
| 639 | warn("cp {} {}\n", source_path, dest_path); | 632 | warn("cp {} {}\n", source_path, dest_path); |
| 640 | } | 633 | } |
| ... | @@ -672,7 +665,7 @@ pub const Builder = struct { | ... | @@ -672,7 +665,7 @@ pub const Builder = struct { |
| 672 | } | 665 | } |
| 673 | } | 666 | } |
| 674 | 667 | ||
| 675 | pub fn findProgram(self: &Builder, names: []const []const u8, paths: []const []const u8) %[]const u8 { | 668 | pub fn findProgram(self: &Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 { |
| 676 | // TODO report error for ambiguous situations | 669 | // TODO report error for ambiguous situations |
| 677 | const exe_extension = (Target { .Native = {}}).exeFileExt(); | 670 | const exe_extension = (Target { .Native = {}}).exeFileExt(); |
| 678 | for (self.search_prefixes.toSliceConst()) |search_prefix| { | 671 | for (self.search_prefixes.toSliceConst()) |search_prefix| { |
| ... | @@ -721,7 +714,7 @@ pub const Builder = struct { | ... | @@ -721,7 +714,7 @@ pub const Builder = struct { |
| 721 | return error.FileNotFound; | 714 | return error.FileNotFound; |
| 722 | } | 715 | } |
| 723 | 716 | ||
| 724 | pub fn exec(self: &Builder, argv: []const []const u8) %[]u8 { | 717 | pub fn exec(self: &Builder, argv: []const []const u8) ![]u8 { |
| 725 | const max_output_size = 100 * 1024; | 718 | const max_output_size = 100 * 1024; |
| 726 | const result = try os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size); | 719 | const result = try os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size); |
| 727 | switch (result.term) { | 720 | switch (result.term) { |
| ... | @@ -1180,12 +1173,12 @@ pub const LibExeObjStep = struct { | ... | @@ -1180,12 +1173,12 @@ pub const LibExeObjStep = struct { |
| 1180 | self.disable_libc = disable; | 1173 | self.disable_libc = disable; |
| 1181 | } | 1174 | } |
| 1182 | 1175 | ||
| 1183 | fn make(step: &Step) %void { | 1176 | fn make(step: &Step) !void { |
| 1184 | const self = @fieldParentPtr(LibExeObjStep, "step", step); | 1177 | const self = @fieldParentPtr(LibExeObjStep, "step", step); |
| 1185 | return if (self.is_zig) self.makeZig() else self.makeC(); | 1178 | return if (self.is_zig) self.makeZig() else self.makeC(); |
| 1186 | } | 1179 | } |
| 1187 | 1180 | ||
| 1188 | fn makeZig(self: &LibExeObjStep) %void { | 1181 | fn makeZig(self: &LibExeObjStep) !void { |
| 1189 | const builder = self.builder; | 1182 | const builder = self.builder; |
| 1190 | 1183 | ||
| 1191 | assert(self.is_zig); | 1184 | assert(self.is_zig); |
| ... | @@ -1396,7 +1389,7 @@ pub const LibExeObjStep = struct { | ... | @@ -1396,7 +1389,7 @@ pub const LibExeObjStep = struct { |
| 1396 | } | 1389 | } |
| 1397 | } | 1390 | } |
| 1398 | 1391 | ||
| 1399 | fn makeC(self: &LibExeObjStep) %void { | 1392 | fn makeC(self: &LibExeObjStep) !void { |
| 1400 | const builder = self.builder; | 1393 | const builder = self.builder; |
| 1401 | 1394 | ||
| 1402 | const cc = builder.getCCExe(); | 1395 | const cc = builder.getCCExe(); |
| ... | @@ -1687,7 +1680,7 @@ pub const TestStep = struct { | ... | @@ -1687,7 +1680,7 @@ pub const TestStep = struct { |
| 1687 | self.exec_cmd_args = args; | 1680 | self.exec_cmd_args = args; |
| 1688 | } | 1681 | } |
| 1689 | 1682 | ||
| 1690 | fn make(step: &Step) %void { | 1683 | fn make(step: &Step) !void { |
| 1691 | const self = @fieldParentPtr(TestStep, "step", step); | 1684 | const self = @fieldParentPtr(TestStep, "step", step); |
| 1692 | const builder = self.builder; | 1685 | const builder = self.builder; |
| 1693 | 1686 | ||
| ... | @@ -1796,7 +1789,7 @@ pub const CommandStep = struct { | ... | @@ -1796,7 +1789,7 @@ pub const CommandStep = struct { |
| 1796 | return self; | 1789 | return self; |
| 1797 | } | 1790 | } |
| 1798 | 1791 | ||
| 1799 | fn make(step: &Step) %void { | 1792 | fn make(step: &Step) !void { |
| 1800 | const self = @fieldParentPtr(CommandStep, "step", step); | 1793 | const self = @fieldParentPtr(CommandStep, "step", step); |
| 1801 | 1794 | ||
| 1802 | const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else self.builder.build_root; | 1795 | const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else self.builder.build_root; |
| ... | @@ -1836,7 +1829,7 @@ const InstallArtifactStep = struct { | ... | @@ -1836,7 +1829,7 @@ const InstallArtifactStep = struct { |
| 1836 | return self; | 1829 | return self; |
| 1837 | } | 1830 | } |
| 1838 | 1831 | ||
| 1839 | fn make(step: &Step) %void { | 1832 | fn make(step: &Step) !void { |
| 1840 | const self = @fieldParentPtr(Self, "step", step); | 1833 | const self = @fieldParentPtr(Self, "step", step); |
| 1841 | const builder = self.builder; | 1834 | const builder = self.builder; |
| 1842 | 1835 | ||
| ... | @@ -1868,7 +1861,7 @@ pub const InstallFileStep = struct { | ... | @@ -1868,7 +1861,7 @@ pub const InstallFileStep = struct { |
| 1868 | }; | 1861 | }; |
| 1869 | } | 1862 | } |
| 1870 | 1863 | ||
| 1871 | fn make(step: &Step) %void { | 1864 | fn make(step: &Step) !void { |
| 1872 | const self = @fieldParentPtr(InstallFileStep, "step", step); | 1865 | const self = @fieldParentPtr(InstallFileStep, "step", step); |
| 1873 | try self.builder.copyFile(self.src_path, self.dest_path); | 1866 | try self.builder.copyFile(self.src_path, self.dest_path); |
| 1874 | } | 1867 | } |
| ... | @@ -1889,7 +1882,7 @@ pub const WriteFileStep = struct { | ... | @@ -1889,7 +1882,7 @@ pub const WriteFileStep = struct { |
| 1889 | }; | 1882 | }; |
| 1890 | } | 1883 | } |
| 1891 | 1884 | ||
| 1892 | fn make(step: &Step) %void { | 1885 | fn make(step: &Step) !void { |
| 1893 | const self = @fieldParentPtr(WriteFileStep, "step", step); | 1886 | const self = @fieldParentPtr(WriteFileStep, "step", step); |
| 1894 | const full_path = self.builder.pathFromRoot(self.file_path); | 1887 | const full_path = self.builder.pathFromRoot(self.file_path); |
| 1895 | const full_path_dir = os.path.dirname(full_path); | 1888 | const full_path_dir = os.path.dirname(full_path); |
| ... | @@ -1917,7 +1910,7 @@ pub const LogStep = struct { | ... | @@ -1917,7 +1910,7 @@ pub const LogStep = struct { |
| 1917 | }; | 1910 | }; |
| 1918 | } | 1911 | } |
| 1919 | 1912 | ||
| 1920 | fn make(step: &Step) %void { | 1913 | fn make(step: &Step) error!void { |
| 1921 | const self = @fieldParentPtr(LogStep, "step", step); | 1914 | const self = @fieldParentPtr(LogStep, "step", step); |
| 1922 | warn("{}", self.data); | 1915 | warn("{}", self.data); |
| 1923 | } | 1916 | } |
| ... | @@ -1936,7 +1929,7 @@ pub const RemoveDirStep = struct { | ... | @@ -1936,7 +1929,7 @@ pub const RemoveDirStep = struct { |
| 1936 | }; | 1929 | }; |
| 1937 | } | 1930 | } |
| 1938 | 1931 | ||
| 1939 | fn make(step: &Step) %void { | 1932 | fn make(step: &Step) !void { |
| 1940 | const self = @fieldParentPtr(RemoveDirStep, "step", step); | 1933 | const self = @fieldParentPtr(RemoveDirStep, "step", step); |
| 1941 | 1934 | ||
| 1942 | const full_path = self.builder.pathFromRoot(self.dir_path); | 1935 | const full_path = self.builder.pathFromRoot(self.dir_path); |
| ... | @@ -1949,12 +1942,12 @@ pub const RemoveDirStep = struct { | ... | @@ -1949,12 +1942,12 @@ pub const RemoveDirStep = struct { |
| 1949 | 1942 | ||
| 1950 | pub const Step = struct { | 1943 | pub const Step = struct { |
| 1951 | name: []const u8, | 1944 | name: []const u8, |
| 1952 | makeFn: fn(self: &Step) %void, | 1945 | makeFn: fn(self: &Step) error!void, |
| 1953 | dependencies: ArrayList(&Step), | 1946 | dependencies: ArrayList(&Step), |
| 1954 | loop_flag: bool, | 1947 | loop_flag: bool, |
| 1955 | done_flag: bool, | 1948 | done_flag: bool, |
| 1956 | 1949 | ||
| 1957 | pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)%void) Step { | 1950 | pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)error!void) Step { |
| 1958 | return Step { | 1951 | return Step { |
| 1959 | .name = name, | 1952 | .name = name, |
| 1960 | .makeFn = makeFn, | 1953 | .makeFn = makeFn, |
| ... | @@ -1967,7 +1960,7 @@ pub const Step = struct { | ... | @@ -1967,7 +1960,7 @@ pub const Step = struct { |
| 1967 | return init(name, allocator, makeNoOp); | 1960 | return init(name, allocator, makeNoOp); |
| 1968 | } | 1961 | } |
| 1969 | 1962 | ||
| 1970 | pub fn make(self: &Step) %void { | 1963 | pub fn make(self: &Step) !void { |
| 1971 | if (self.done_flag) | 1964 | if (self.done_flag) |
| 1972 | return; | 1965 | return; |
| 1973 | 1966 | ||
| ... | @@ -1979,11 +1972,11 @@ pub const Step = struct { | ... | @@ -1979,11 +1972,11 @@ pub const Step = struct { |
| 1979 | self.dependencies.append(other) catch unreachable; | 1972 | self.dependencies.append(other) catch unreachable; |
| 1980 | } | 1973 | } |
| 1981 | 1974 | ||
| 1982 | fn makeNoOp(self: &Step) %void {} | 1975 | fn makeNoOp(self: &Step) error!void {} |
| 1983 | }; | 1976 | }; |
| 1984 | 1977 | ||
| 1985 | fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_major_only: []const u8, | 1978 | fn 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 |
| 1987 | { | 1980 | { |
| 1988 | const out_dir = os.path.dirname(output_path); | 1981 | const out_dir = os.path.dirname(output_path); |
| 1989 | const out_basename = os.path.basename(output_path); | 1982 | const out_basename = os.path.basename(output_path); |
std/c/index.zig+1-1| ... | @@ -20,7 +20,7 @@ pub extern "c" fn open(path: &const u8, oflag: c_int, ...) c_int; | ... | @@ -20,7 +20,7 @@ pub extern "c" fn open(path: &const u8, oflag: c_int, ...) c_int; |
| 20 | pub extern "c" fn raise(sig: c_int) c_int; | 20 | pub extern "c" fn raise(sig: c_int) c_int; |
| 21 | pub extern "c" fn read(fd: c_int, buf: &c_void, nbyte: usize) isize; | 21 | pub extern "c" fn read(fd: c_int, buf: &c_void, nbyte: usize) isize; |
| 22 | pub extern "c" fn stat(noalias path: &const u8, noalias buf: &Stat) c_int; | 22 | pub extern "c" fn stat(noalias path: &const u8, noalias buf: &Stat) c_int; |
| 23 | pub extern "c" fn write(fd: c_int, buf: &const c_void, nbyte: usize) c_int; | 23 | pub extern "c" fn write(fd: c_int, buf: &const c_void, nbyte: usize) isize; |
| 24 | pub extern "c" fn mmap(addr: ?&c_void, len: usize, prot: c_int, flags: c_int, | 24 | pub extern "c" fn mmap(addr: ?&c_void, len: usize, prot: c_int, flags: c_int, |
| 25 | fd: c_int, offset: isize) ?&c_void; | 25 | fd: c_int, offset: isize) ?&c_void; |
| 26 | pub extern "c" fn munmap(addr: &c_void, len: usize) c_int; | 26 | pub extern "c" fn munmap(addr: &c_void, len: usize) c_int; |
std/crypto/throughput_test.zig+1-1| ... | @@ -18,7 +18,7 @@ const c = @cImport({ | ... | @@ -18,7 +18,7 @@ const c = @cImport({ |
| 18 | 18 | ||
| 19 | const Mb = 1024 * 1024; | 19 | const Mb = 1024 * 1024; |
| 20 | 20 | ||
| 21 | pub fn main() %void { | 21 | pub fn main() !void { |
| 22 | var stdout_file = try std.io.getStdOut(); | 22 | var stdout_file = try std.io.getStdOut(); |
| 23 | var stdout_out_stream = std.io.FileOutStream.init(&stdout_file); | 23 | var stdout_out_stream = std.io.FileOutStream.init(&stdout_file); |
| 24 | const stdout = &stdout_out_stream.stream; | 24 | const stdout = &stdout_out_stream.stream; |
std/cstr.zig+2-2| ... | @@ -42,7 +42,7 @@ fn testCStrFnsImpl() void { | ... | @@ -42,7 +42,7 @@ fn testCStrFnsImpl() void { |
| 42 | /// Returns a mutable slice with exactly the same size which is guaranteed to | 42 | /// Returns a mutable slice with exactly the same size which is guaranteed to |
| 43 | /// have a null byte after it. | 43 | /// have a null byte after it. |
| 44 | /// Caller owns the returned memory. | 44 | /// Caller owns the returned memory. |
| 45 | pub fn addNullByte(allocator: &mem.Allocator, slice: []const u8) %[]u8 { | 45 | pub fn addNullByte(allocator: &mem.Allocator, slice: []const u8) ![]u8 { |
| 46 | const result = try allocator.alloc(u8, slice.len + 1); | 46 | const result = try allocator.alloc(u8, slice.len + 1); |
| 47 | mem.copy(u8, result, slice); | 47 | mem.copy(u8, result, slice); |
| 48 | result[slice.len] = 0; | 48 | result[slice.len] = 0; |
| ... | @@ -56,7 +56,7 @@ pub const NullTerminated2DArray = struct { | ... | @@ -56,7 +56,7 @@ pub const NullTerminated2DArray = struct { |
| 56 | 56 | ||
| 57 | /// Takes N lists of strings, concatenates the lists together, and adds a null terminator | 57 | /// Takes N lists of strings, concatenates the lists together, and adds a null terminator |
| 58 | /// Caller must deinit result | 58 | /// Caller must deinit result |
| 59 | pub fn fromSlices(allocator: &mem.Allocator, slices: []const []const []const u8) %NullTerminated2DArray { | 59 | pub fn fromSlices(allocator: &mem.Allocator, slices: []const []const []const u8) !NullTerminated2DArray { |
| 60 | var new_len: usize = 1; // 1 for the list null | 60 | var new_len: usize = 1; // 1 for the list null |
| 61 | var byte_count: usize = 0; | 61 | var byte_count: usize = 0; |
| 62 | for (slices) |slice| { | 62 | for (slices) |slice| { |
std/debug/failing_allocator.zig+2-2| ... | @@ -28,7 +28,7 @@ pub const FailingAllocator = struct { | ... | @@ -28,7 +28,7 @@ pub const FailingAllocator = struct { |
| 28 | }; | 28 | }; |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | fn alloc(allocator: &mem.Allocator, n: usize, alignment: u29) %[]u8 { | 31 | fn alloc(allocator: &mem.Allocator, n: usize, alignment: u29) ![]u8 { |
| 32 | const self = @fieldParentPtr(FailingAllocator, "allocator", allocator); | 32 | const self = @fieldParentPtr(FailingAllocator, "allocator", allocator); |
| 33 | if (self.index == self.fail_index) { | 33 | if (self.index == self.fail_index) { |
| 34 | return error.OutOfMemory; | 34 | return error.OutOfMemory; |
| ... | @@ -39,7 +39,7 @@ pub const FailingAllocator = struct { | ... | @@ -39,7 +39,7 @@ pub const FailingAllocator = struct { |
| 39 | return result; | 39 | return result; |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | fn realloc(allocator: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: u29) %[]u8 { | 42 | fn realloc(allocator: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 { |
| 43 | const self = @fieldParentPtr(FailingAllocator, "allocator", allocator); | 43 | const self = @fieldParentPtr(FailingAllocator, "allocator", allocator); |
| 44 | if (new_size <= old_mem.len) { | 44 | if (new_size <= old_mem.len) { |
| 45 | self.freed_bytes += old_mem.len - new_size; | 45 | self.freed_bytes += old_mem.len - new_size; |
std/debug/index.zig+52-52| ... | @@ -10,26 +10,17 @@ const builtin = @import("builtin"); | ... | @@ -10,26 +10,17 @@ const builtin = @import("builtin"); |
| 10 | 10 | ||
| 11 | pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator; | 11 | pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator; |
| 12 | 12 | ||
| 13 | error MissingDebugInfo; | ||
| 14 | error InvalidDebugInfo; | ||
| 15 | error UnsupportedDebugInfo; | ||
| 16 | error UnknownObjectFormat; | ||
| 17 | error TodoSupportCoffDebugInfo; | ||
| 18 | error TodoSupportMachoDebugInfo; | ||
| 19 | error TodoSupportCOFFDebugInfo; | ||
| 20 | |||
| 21 | |||
| 22 | /// Tries to write to stderr, unbuffered, and ignores any error returned. | 13 | /// Tries to write to stderr, unbuffered, and ignores any error returned. |
| 23 | /// Does not append a newline. | 14 | /// Does not append a newline. |
| 24 | /// TODO atomic/multithread support | 15 | /// TODO atomic/multithread support |
| 25 | var stderr_file: io.File = undefined; | 16 | var stderr_file: io.File = undefined; |
| 26 | var stderr_file_out_stream: io.FileOutStream = undefined; | 17 | var stderr_file_out_stream: io.FileOutStream = undefined; |
| 27 | var stderr_stream: ?&io.OutStream = null; | 18 | var stderr_stream: ?&io.OutStream(io.FileOutStream.Error) = null; |
| 28 | pub fn warn(comptime fmt: []const u8, args: ...) void { | 19 | pub fn warn(comptime fmt: []const u8, args: ...) void { |
| 29 | const stderr = getStderrStream() catch return; | 20 | const stderr = getStderrStream() catch return; |
| 30 | stderr.print(fmt, args) catch return; | 21 | stderr.print(fmt, args) catch return; |
| 31 | } | 22 | } |
| 32 | fn getStderrStream() %&io.OutStream { | 23 | fn getStderrStream() !&io.OutStream(io.FileOutStream.Error) { |
| 33 | if (stderr_stream) |st| { | 24 | if (stderr_stream) |st| { |
| 34 | return st; | 25 | return st; |
| 35 | } else { | 26 | } else { |
| ... | @@ -42,7 +33,7 @@ fn getStderrStream() %&io.OutStream { | ... | @@ -42,7 +33,7 @@ fn getStderrStream() %&io.OutStream { |
| 42 | } | 33 | } |
| 43 | 34 | ||
| 44 | var self_debug_info: ?&ElfStackTrace = null; | 35 | var self_debug_info: ?&ElfStackTrace = null; |
| 45 | pub fn getSelfDebugInfo() %&ElfStackTrace { | 36 | pub fn getSelfDebugInfo() !&ElfStackTrace { |
| 46 | if (self_debug_info) |info| { | 37 | if (self_debug_info) |info| { |
| 47 | return info; | 38 | return info; |
| 48 | } else { | 39 | } else { |
| ... | @@ -149,11 +140,8 @@ const WHITE = "\x1b[37;1m"; | ... | @@ -149,11 +140,8 @@ const WHITE = "\x1b[37;1m"; |
| 149 | const DIM = "\x1b[2m"; | 140 | const DIM = "\x1b[2m"; |
| 150 | const RESET = "\x1b[0m"; | 141 | const RESET = "\x1b[0m"; |
| 151 | 142 | ||
| 152 | error PathNotFound; | 143 | pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var, allocator: &mem.Allocator, |
| 153 | error InvalidDebugInfo; | 144 | debug_info: &ElfStackTrace, tty_color: bool) !void |
| 154 | |||
| 155 | pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator, | ||
| 156 | debug_info: &ElfStackTrace, tty_color: bool) %void | ||
| 157 | { | 145 | { |
| 158 | var frame_index: usize = undefined; | 146 | var frame_index: usize = undefined; |
| 159 | var frames_left: usize = undefined; | 147 | var frames_left: usize = undefined; |
| ... | @@ -174,8 +162,8 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.O | ... | @@ -174,8 +162,8 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.O |
| 174 | } | 162 | } |
| 175 | } | 163 | } |
| 176 | 164 | ||
| 177 | pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, | 165 | pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator, |
| 178 | debug_info: &ElfStackTrace, tty_color: bool, ignore_frame_count: usize) %void | 166 | debug_info: &ElfStackTrace, tty_color: bool, ignore_frame_count: usize) !void |
| 179 | { | 167 | { |
| 180 | var ignored_count: usize = 0; | 168 | var ignored_count: usize = 0; |
| 181 | 169 | ||
| ... | @@ -191,7 +179,7 @@ pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocat | ... | @@ -191,7 +179,7 @@ pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocat |
| 191 | } | 179 | } |
| 192 | } | 180 | } |
| 193 | 181 | ||
| 194 | fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, address: usize) %void { | 182 | fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: var, address: usize) !void { |
| 195 | if (builtin.os == builtin.Os.windows) { | 183 | if (builtin.os == builtin.Os.windows) { |
| 196 | return error.UnsupportedDebugInfo; | 184 | return error.UnsupportedDebugInfo; |
| 197 | } | 185 | } |
| ... | @@ -221,7 +209,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a | ... | @@ -221,7 +209,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a |
| 221 | try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n"); | 209 | try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n"); |
| 222 | } | 210 | } |
| 223 | } else |err| switch (err) { | 211 | } else |err| switch (err) { |
| 224 | error.EndOfFile, error.PathNotFound => {}, | 212 | error.EndOfFile => {}, |
| 225 | else => return err, | 213 | else => return err, |
| 226 | } | 214 | } |
| 227 | } else |err| switch (err) { | 215 | } else |err| switch (err) { |
| ... | @@ -232,7 +220,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a | ... | @@ -232,7 +220,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a |
| 232 | } | 220 | } |
| 233 | } | 221 | } |
| 234 | 222 | ||
| 235 | pub fn openSelfDebugInfo(allocator: &mem.Allocator) %&ElfStackTrace { | 223 | pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace { |
| 236 | switch (builtin.object_format) { | 224 | switch (builtin.object_format) { |
| 237 | builtin.ObjectFormat.elf => { | 225 | builtin.ObjectFormat.elf => { |
| 238 | const st = try allocator.create(ElfStackTrace); | 226 | const st = try allocator.create(ElfStackTrace); |
| ... | @@ -276,7 +264,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) %&ElfStackTrace { | ... | @@ -276,7 +264,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) %&ElfStackTrace { |
| 276 | } | 264 | } |
| 277 | } | 265 | } |
| 278 | 266 | ||
| 279 | fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_info: &const LineInfo) %void { | 267 | fn printLineFromFile(allocator: &mem.Allocator, out_stream: var, line_info: &const LineInfo) !void { |
| 280 | var f = try io.File.openRead(line_info.file_name, allocator); | 268 | var f = try io.File.openRead(line_info.file_name, allocator); |
| 281 | defer f.close(); | 269 | defer f.close(); |
| 282 | // TODO fstat and make sure that the file has the correct size | 270 | // TODO fstat and make sure that the file has the correct size |
| ... | @@ -324,7 +312,7 @@ pub const ElfStackTrace = struct { | ... | @@ -324,7 +312,7 @@ pub const ElfStackTrace = struct { |
| 324 | return self.abbrev_table_list.allocator; | 312 | return self.abbrev_table_list.allocator; |
| 325 | } | 313 | } |
| 326 | 314 | ||
| 327 | pub fn readString(self: &ElfStackTrace) %[]u8 { | 315 | pub fn readString(self: &ElfStackTrace) ![]u8 { |
| 328 | var in_file_stream = io.FileInStream.init(&self.self_exe_file); | 316 | var in_file_stream = io.FileInStream.init(&self.self_exe_file); |
| 329 | const in_stream = &in_file_stream.stream; | 317 | const in_stream = &in_file_stream.stream; |
| 330 | return readStringRaw(self.allocator(), in_stream); | 318 | return readStringRaw(self.allocator(), in_stream); |
| ... | @@ -387,7 +375,7 @@ const Constant = struct { | ... | @@ -387,7 +375,7 @@ const Constant = struct { |
| 387 | payload: []u8, | 375 | payload: []u8, |
| 388 | signed: bool, | 376 | signed: bool, |
| 389 | 377 | ||
| 390 | fn asUnsignedLe(self: &const Constant) %u64 { | 378 | fn asUnsignedLe(self: &const Constant) !u64 { |
| 391 | if (self.payload.len > @sizeOf(u64)) | 379 | if (self.payload.len > @sizeOf(u64)) |
| 392 | return error.InvalidDebugInfo; | 380 | return error.InvalidDebugInfo; |
| 393 | if (self.signed) | 381 | if (self.signed) |
| ... | @@ -414,7 +402,7 @@ const Die = struct { | ... | @@ -414,7 +402,7 @@ const Die = struct { |
| 414 | return null; | 402 | return null; |
| 415 | } | 403 | } |
| 416 | 404 | ||
| 417 | fn getAttrAddr(self: &const Die, id: u64) %u64 { | 405 | fn getAttrAddr(self: &const Die, id: u64) !u64 { |
| 418 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; | 406 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; |
| 419 | return switch (*form_value) { | 407 | return switch (*form_value) { |
| 420 | FormValue.Address => |value| value, | 408 | FormValue.Address => |value| value, |
| ... | @@ -422,7 +410,7 @@ const Die = struct { | ... | @@ -422,7 +410,7 @@ const Die = struct { |
| 422 | }; | 410 | }; |
| 423 | } | 411 | } |
| 424 | 412 | ||
| 425 | fn getAttrSecOffset(self: &const Die, id: u64) %u64 { | 413 | fn getAttrSecOffset(self: &const Die, id: u64) !u64 { |
| 426 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; | 414 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; |
| 427 | return switch (*form_value) { | 415 | return switch (*form_value) { |
| 428 | FormValue.Const => |value| value.asUnsignedLe(), | 416 | FormValue.Const => |value| value.asUnsignedLe(), |
| ... | @@ -431,7 +419,7 @@ const Die = struct { | ... | @@ -431,7 +419,7 @@ const Die = struct { |
| 431 | }; | 419 | }; |
| 432 | } | 420 | } |
| 433 | 421 | ||
| 434 | fn getAttrUnsignedLe(self: &const Die, id: u64) %u64 { | 422 | fn getAttrUnsignedLe(self: &const Die, id: u64) !u64 { |
| 435 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; | 423 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; |
| 436 | return switch (*form_value) { | 424 | return switch (*form_value) { |
| 437 | FormValue.Const => |value| value.asUnsignedLe(), | 425 | FormValue.Const => |value| value.asUnsignedLe(), |
| ... | @@ -439,7 +427,7 @@ const Die = struct { | ... | @@ -439,7 +427,7 @@ const Die = struct { |
| 439 | }; | 427 | }; |
| 440 | } | 428 | } |
| 441 | 429 | ||
| 442 | fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) %[]u8 { | 430 | fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) ![]u8 { |
| 443 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; | 431 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; |
| 444 | return switch (*form_value) { | 432 | return switch (*form_value) { |
| 445 | FormValue.String => |value| value, | 433 | FormValue.String => |value| value, |
| ... | @@ -512,7 +500,7 @@ const LineNumberProgram = struct { | ... | @@ -512,7 +500,7 @@ const LineNumberProgram = struct { |
| 512 | }; | 500 | }; |
| 513 | } | 501 | } |
| 514 | 502 | ||
| 515 | pub fn checkLineMatch(self: &LineNumberProgram) %?LineInfo { | 503 | pub fn checkLineMatch(self: &LineNumberProgram) !?LineInfo { |
| 516 | if (self.target_address >= self.prev_address and self.target_address < self.address) { | 504 | if (self.target_address >= self.prev_address and self.target_address < self.address) { |
| 517 | const file_entry = if (self.prev_file == 0) { | 505 | const file_entry = if (self.prev_file == 0) { |
| 518 | return error.MissingDebugInfo; | 506 | return error.MissingDebugInfo; |
| ... | @@ -544,7 +532,7 @@ const LineNumberProgram = struct { | ... | @@ -544,7 +532,7 @@ const LineNumberProgram = struct { |
| 544 | } | 532 | } |
| 545 | }; | 533 | }; |
| 546 | 534 | ||
| 547 | fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) %[]u8 { | 535 | fn readStringRaw(allocator: &mem.Allocator, in_stream: var) ![]u8 { |
| 548 | var buf = ArrayList(u8).init(allocator); | 536 | var buf = ArrayList(u8).init(allocator); |
| 549 | while (true) { | 537 | while (true) { |
| 550 | const byte = try in_stream.readByte(); | 538 | const byte = try in_stream.readByte(); |
| ... | @@ -555,58 +543,70 @@ fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) %[]u8 { | ... | @@ -555,58 +543,70 @@ fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) %[]u8 { |
| 555 | return buf.toSlice(); | 543 | return buf.toSlice(); |
| 556 | } | 544 | } |
| 557 | 545 | ||
| 558 | fn getString(st: &ElfStackTrace, offset: u64) %[]u8 { | 546 | fn getString(st: &ElfStackTrace, offset: u64) ![]u8 { |
| 559 | const pos = st.debug_str.offset + offset; | 547 | const pos = st.debug_str.offset + offset; |
| 560 | try st.self_exe_file.seekTo(pos); | 548 | try st.self_exe_file.seekTo(pos); |
| 561 | return st.readString(); | 549 | return st.readString(); |
| 562 | } | 550 | } |
| 563 | 551 | ||
| 564 | fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) %[]u8 { | 552 | fn readAllocBytes(allocator: &mem.Allocator, in_stream: var, size: usize) ![]u8 { |
| 565 | const buf = try global_allocator.alloc(u8, size); | 553 | const buf = try global_allocator.alloc(u8, size); |
| 566 | errdefer global_allocator.free(buf); | 554 | errdefer global_allocator.free(buf); |
| 567 | if ((try in_stream.read(buf)) < size) return error.EndOfFile; | 555 | if ((try in_stream.read(buf)) < size) return error.EndOfFile; |
| 568 | return buf; | 556 | return buf; |
| 569 | } | 557 | } |
| 570 | 558 | ||
| 571 | fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) %FormValue { | 559 | fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue { |
| 572 | const buf = try readAllocBytes(allocator, in_stream, size); | 560 | const buf = try readAllocBytes(allocator, in_stream, size); |
| 573 | return FormValue { .Block = buf }; | 561 | return FormValue { .Block = buf }; |
| 574 | } | 562 | } |
| 575 | 563 | ||
| 576 | fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) %FormValue { | 564 | fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue { |
| 577 | const block_len = try in_stream.readVarInt(builtin.Endian.Little, usize, size); | 565 | const block_len = try in_stream.readVarInt(builtin.Endian.Little, usize, size); |
| 578 | return parseFormValueBlockLen(allocator, in_stream, block_len); | 566 | return parseFormValueBlockLen(allocator, in_stream, block_len); |
| 579 | } | 567 | } |
| 580 | 568 | ||
| 581 | fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) %FormValue { | 569 | fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue { |
| 582 | return FormValue { .Const = Constant { | 570 | return FormValue { .Const = Constant { |
| 583 | .signed = signed, | 571 | .signed = signed, |
| 584 | .payload = try readAllocBytes(allocator, in_stream, size), | 572 | .payload = try readAllocBytes(allocator, in_stream, size), |
| 585 | }}; | 573 | }}; |
| 586 | } | 574 | } |
| 587 | 575 | ||
| 588 | fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) %u64 { | 576 | fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 { |
| 589 | return if (is_64) try in_stream.readIntLe(u64) | 577 | return if (is_64) try in_stream.readIntLe(u64) |
| 590 | else u64(try in_stream.readIntLe(u32)) ; | 578 | else u64(try in_stream.readIntLe(u32)) ; |
| 591 | } | 579 | } |
| 592 | 580 | ||
| 593 | fn parseFormValueTargetAddrSize(in_stream: &io.InStream) %u64 { | 581 | fn parseFormValueTargetAddrSize(in_stream: var) !u64 { |
| 594 | return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32)) | 582 | return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32)) |
| 595 | else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) | 583 | else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) |
| 596 | else unreachable; | 584 | else unreachable; |
| 597 | } | 585 | } |
| 598 | 586 | ||
| 599 | fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) %FormValue { | 587 | fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue { |
| 600 | const buf = try readAllocBytes(allocator, in_stream, size); | 588 | const buf = try readAllocBytes(allocator, in_stream, size); |
| 601 | return FormValue { .Ref = buf }; | 589 | return FormValue { .Ref = buf }; |
| 602 | } | 590 | } |
| 603 | 591 | ||
| 604 | fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptime T: type) %FormValue { | 592 | fn parseFormValueRef(allocator: &mem.Allocator, in_stream: var, comptime T: type) !FormValue { |
| 605 | const block_len = try in_stream.readIntLe(T); | 593 | const block_len = try in_stream.readIntLe(T); |
| 606 | return parseFormValueRefLen(allocator, in_stream, block_len); | 594 | return parseFormValueRefLen(allocator, in_stream, block_len); |
| 607 | } | 595 | } |
| 608 | 596 | ||
| 609 | fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool) %FormValue { | 597 | const ParseFormValueError = error { |
| 598 | EndOfStream, | ||
| 599 | Io, | ||
| 600 | BadFd, | ||
| 601 | Unexpected, | ||
| 602 | InvalidDebugInfo, | ||
| 603 | EndOfFile, | ||
| 604 | OutOfMemory, | ||
| 605 | }; | ||
| 606 | |||
| 607 | fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64: bool) | ||
| 608 | ParseFormValueError!FormValue | ||
| 609 | { | ||
| 610 | return switch (form_id) { | 610 | return switch (form_id) { |
| 611 | DW.FORM_addr => FormValue { .Address = try parseFormValueTargetAddrSize(in_stream) }, | 611 | DW.FORM_addr => FormValue { .Address = try parseFormValueTargetAddrSize(in_stream) }, |
| 612 | DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1), | 612 | DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1), |
| ... | @@ -656,7 +656,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u | ... | @@ -656,7 +656,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u |
| 656 | }; | 656 | }; |
| 657 | } | 657 | } |
| 658 | 658 | ||
| 659 | fn parseAbbrevTable(st: &ElfStackTrace) %AbbrevTable { | 659 | fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable { |
| 660 | const in_file = &st.self_exe_file; | 660 | const in_file = &st.self_exe_file; |
| 661 | var in_file_stream = io.FileInStream.init(in_file); | 661 | var in_file_stream = io.FileInStream.init(in_file); |
| 662 | const in_stream = &in_file_stream.stream; | 662 | const in_stream = &in_file_stream.stream; |
| ... | @@ -688,7 +688,7 @@ fn parseAbbrevTable(st: &ElfStackTrace) %AbbrevTable { | ... | @@ -688,7 +688,7 @@ fn parseAbbrevTable(st: &ElfStackTrace) %AbbrevTable { |
| 688 | 688 | ||
| 689 | /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found, | 689 | /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found, |
| 690 | /// seeks in the stream and parses it. | 690 | /// seeks in the stream and parses it. |
| 691 | fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) %&const AbbrevTable { | 691 | fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) !&const AbbrevTable { |
| 692 | for (st.abbrev_table_list.toSlice()) |*header| { | 692 | for (st.abbrev_table_list.toSlice()) |*header| { |
| 693 | if (header.offset == abbrev_offset) { | 693 | if (header.offset == abbrev_offset) { |
| 694 | return &header.table; | 694 | return &header.table; |
| ... | @@ -710,7 +710,7 @@ fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) ?&con | ... | @@ -710,7 +710,7 @@ fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) ?&con |
| 710 | return null; | 710 | return null; |
| 711 | } | 711 | } |
| 712 | 712 | ||
| 713 | fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) %Die { | 713 | fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) !Die { |
| 714 | const in_file = &st.self_exe_file; | 714 | const in_file = &st.self_exe_file; |
| 715 | var in_file_stream = io.FileInStream.init(in_file); | 715 | var in_file_stream = io.FileInStream.init(in_file); |
| 716 | const in_stream = &in_file_stream.stream; | 716 | const in_stream = &in_file_stream.stream; |
| ... | @@ -732,7 +732,7 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) % | ... | @@ -732,7 +732,7 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) % |
| 732 | return result; | 732 | return result; |
| 733 | } | 733 | } |
| 734 | 734 | ||
| 735 | fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, target_address: usize) %LineInfo { | 735 | fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, target_address: usize) !LineInfo { |
| 736 | const compile_unit_cwd = try compile_unit.die.getAttrString(st, DW.AT_comp_dir); | 736 | const compile_unit_cwd = try compile_unit.die.getAttrString(st, DW.AT_comp_dir); |
| 737 | 737 | ||
| 738 | const in_file = &st.self_exe_file; | 738 | const in_file = &st.self_exe_file; |
| ... | @@ -747,7 +747,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe | ... | @@ -747,7 +747,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe |
| 747 | try in_file.seekTo(this_offset); | 747 | try in_file.seekTo(this_offset); |
| 748 | 748 | ||
| 749 | var is_64: bool = undefined; | 749 | var is_64: bool = undefined; |
| 750 | const unit_length = try readInitialLength(in_stream, &is_64); | 750 | const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64); |
| 751 | if (unit_length == 0) | 751 | if (unit_length == 0) |
| 752 | return error.MissingDebugInfo; | 752 | return error.MissingDebugInfo; |
| 753 | const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); | 753 | const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); |
| ... | @@ -910,7 +910,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe | ... | @@ -910,7 +910,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe |
| 910 | return error.MissingDebugInfo; | 910 | return error.MissingDebugInfo; |
| 911 | } | 911 | } |
| 912 | 912 | ||
| 913 | fn scanAllCompileUnits(st: &ElfStackTrace) %void { | 913 | fn scanAllCompileUnits(st: &ElfStackTrace) !void { |
| 914 | const debug_info_end = st.debug_info.offset + st.debug_info.size; | 914 | const debug_info_end = st.debug_info.offset + st.debug_info.size; |
| 915 | var this_unit_offset = st.debug_info.offset; | 915 | var this_unit_offset = st.debug_info.offset; |
| 916 | var cu_index: usize = 0; | 916 | var cu_index: usize = 0; |
| ... | @@ -922,7 +922,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) %void { | ... | @@ -922,7 +922,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) %void { |
| 922 | try st.self_exe_file.seekTo(this_unit_offset); | 922 | try st.self_exe_file.seekTo(this_unit_offset); |
| 923 | 923 | ||
| 924 | var is_64: bool = undefined; | 924 | var is_64: bool = undefined; |
| 925 | const unit_length = try readInitialLength(in_stream, &is_64); | 925 | const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64); |
| 926 | if (unit_length == 0) | 926 | if (unit_length == 0) |
| 927 | return; | 927 | return; |
| 928 | const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); | 928 | const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); |
| ... | @@ -986,7 +986,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) %void { | ... | @@ -986,7 +986,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) %void { |
| 986 | } | 986 | } |
| 987 | } | 987 | } |
| 988 | 988 | ||
| 989 | fn findCompileUnit(st: &ElfStackTrace, target_address: u64) %&const CompileUnit { | 989 | fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit { |
| 990 | var in_file_stream = io.FileInStream.init(&st.self_exe_file); | 990 | var in_file_stream = io.FileInStream.init(&st.self_exe_file); |
| 991 | const in_stream = &in_file_stream.stream; | 991 | const in_stream = &in_file_stream.stream; |
| 992 | for (st.compile_unit_list.toSlice()) |*compile_unit| { | 992 | for (st.compile_unit_list.toSlice()) |*compile_unit| { |
| ... | @@ -1022,7 +1022,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) %&const CompileUnit | ... | @@ -1022,7 +1022,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) %&const CompileUnit |
| 1022 | return error.MissingDebugInfo; | 1022 | return error.MissingDebugInfo; |
| 1023 | } | 1023 | } |
| 1024 | 1024 | ||
| 1025 | fn readInitialLength(in_stream: &io.InStream, is_64: &bool) %u64 { | 1025 | fn readInitialLength(comptime E: type, in_stream: &io.InStream(E), is_64: &bool) !u64 { |
| 1026 | const first_32_bits = try in_stream.readIntLe(u32); | 1026 | const first_32_bits = try in_stream.readIntLe(u32); |
| 1027 | *is_64 = (first_32_bits == 0xffffffff); | 1027 | *is_64 = (first_32_bits == 0xffffffff); |
| 1028 | if (*is_64) { | 1028 | if (*is_64) { |
| ... | @@ -1033,7 +1033,7 @@ fn readInitialLength(in_stream: &io.InStream, is_64: &bool) %u64 { | ... | @@ -1033,7 +1033,7 @@ fn readInitialLength(in_stream: &io.InStream, is_64: &bool) %u64 { |
| 1033 | } | 1033 | } |
| 1034 | } | 1034 | } |
| 1035 | 1035 | ||
| 1036 | fn readULeb128(in_stream: &io.InStream) %u64 { | 1036 | fn readULeb128(in_stream: var) !u64 { |
| 1037 | var result: u64 = 0; | 1037 | var result: u64 = 0; |
| 1038 | var shift: usize = 0; | 1038 | var shift: usize = 0; |
| 1039 | 1039 | ||
| ... | @@ -1054,7 +1054,7 @@ fn readULeb128(in_stream: &io.InStream) %u64 { | ... | @@ -1054,7 +1054,7 @@ fn readULeb128(in_stream: &io.InStream) %u64 { |
| 1054 | } | 1054 | } |
| 1055 | } | 1055 | } |
| 1056 | 1056 | ||
| 1057 | fn readILeb128(in_stream: &io.InStream) %i64 { | 1057 | fn readILeb128(in_stream: var) !i64 { |
| 1058 | var result: i64 = 0; | 1058 | var result: i64 = 0; |
| 1059 | var shift: usize = 0; | 1059 | var shift: usize = 0; |
| 1060 | 1060 |
std/elf.zig+4-6| ... | @@ -6,8 +6,6 @@ const mem = std.mem; | ... | @@ -6,8 +6,6 @@ const mem = std.mem; |
| 6 | const debug = std.debug; | 6 | const debug = std.debug; |
| 7 | const InStream = std.stream.InStream; | 7 | const InStream = std.stream.InStream; |
| 8 | 8 | ||
| 9 | error InvalidFormat; | ||
| 10 | |||
| 11 | pub const SHT_NULL = 0; | 9 | pub const SHT_NULL = 0; |
| 12 | pub const SHT_PROGBITS = 1; | 10 | pub const SHT_PROGBITS = 1; |
| 13 | pub const SHT_SYMTAB = 2; | 11 | pub const SHT_SYMTAB = 2; |
| ... | @@ -81,14 +79,14 @@ pub const Elf = struct { | ... | @@ -81,14 +79,14 @@ pub const Elf = struct { |
| 81 | prealloc_file: io.File, | 79 | prealloc_file: io.File, |
| 82 | 80 | ||
| 83 | /// Call close when done. | 81 | /// Call close when done. |
| 84 | pub fn openPath(elf: &Elf, allocator: &mem.Allocator, path: []const u8) %void { | 82 | pub fn openPath(elf: &Elf, allocator: &mem.Allocator, path: []const u8) !void { |
| 85 | try elf.prealloc_file.open(path); | 83 | try elf.prealloc_file.open(path); |
| 86 | try elf.openFile(allocator, &elf.prealloc_file); | 84 | try elf.openFile(allocator, &elf.prealloc_file); |
| 87 | elf.auto_close_stream = true; | 85 | elf.auto_close_stream = true; |
| 88 | } | 86 | } |
| 89 | 87 | ||
| 90 | /// Call close when done. | 88 | /// Call close when done. |
| 91 | pub fn openFile(elf: &Elf, allocator: &mem.Allocator, file: &io.File) %void { | 89 | pub fn openFile(elf: &Elf, allocator: &mem.Allocator, file: &io.File) !void { |
| 92 | elf.allocator = allocator; | 90 | elf.allocator = allocator; |
| 93 | elf.in_file = file; | 91 | elf.in_file = file; |
| 94 | elf.auto_close_stream = false; | 92 | elf.auto_close_stream = false; |
| ... | @@ -239,7 +237,7 @@ pub const Elf = struct { | ... | @@ -239,7 +237,7 @@ pub const Elf = struct { |
| 239 | elf.in_file.close(); | 237 | elf.in_file.close(); |
| 240 | } | 238 | } |
| 241 | 239 | ||
| 242 | pub fn findSection(elf: &Elf, name: []const u8) %?&SectionHeader { | 240 | pub fn findSection(elf: &Elf, name: []const u8) !?&SectionHeader { |
| 243 | var file_stream = io.FileInStream.init(elf.in_file); | 241 | var file_stream = io.FileInStream.init(elf.in_file); |
| 244 | const in = &file_stream.stream; | 242 | const in = &file_stream.stream; |
| 245 | 243 | ||
| ... | @@ -263,7 +261,7 @@ pub const Elf = struct { | ... | @@ -263,7 +261,7 @@ pub const Elf = struct { |
| 263 | return null; | 261 | return null; |
| 264 | } | 262 | } |
| 265 | 263 | ||
| 266 | pub fn seekToSection(elf: &Elf, elf_section: &SectionHeader) %void { | 264 | pub fn seekToSection(elf: &Elf, elf_section: &SectionHeader) !void { |
| 267 | try elf.in_file.seekTo(elf_section.offset); | 265 | try elf.in_file.seekTo(elf_section.offset); |
| 268 | } | 266 | } |
| 269 | }; | 267 | }; |
std/fmt/index.zig+56-52| ... | @@ -24,8 +24,8 @@ const State = enum { // TODO put inside format function and make sure the name a | ... | @@ -24,8 +24,8 @@ const State = enum { // TODO put inside format function and make sure the name a |
| 24 | /// Renders fmt string with args, calling output with slices of bytes. | 24 | /// Renders fmt string with args, calling output with slices of bytes. |
| 25 | /// If `output` returns an error, the error is returned from `format` and | 25 | /// If `output` returns an error, the error is returned from `format` and |
| 26 | /// `output` is not called again. | 26 | /// `output` is not called again. |
| 27 | pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, | 27 | pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void, |
| 28 | comptime fmt: []const u8, args: ...) %void | 28 | comptime fmt: []const u8, args: ...) Errors!void |
| 29 | { | 29 | { |
| 30 | comptime var start_index = 0; | 30 | comptime var start_index = 0; |
| 31 | comptime var state = State.Start; | 31 | comptime var state = State.Start; |
| ... | @@ -58,7 +58,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, | ... | @@ -58,7 +58,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, |
| 58 | start_index = i; | 58 | start_index = i; |
| 59 | }, | 59 | }, |
| 60 | '}' => { | 60 | '}' => { |
| 61 | try formatValue(args[next_arg], context, output); | 61 | try formatValue(args[next_arg], context, Errors, output); |
| 62 | next_arg += 1; | 62 | next_arg += 1; |
| 63 | state = State.Start; | 63 | state = State.Start; |
| 64 | start_index = i + 1; | 64 | start_index = i + 1; |
| ... | @@ -110,7 +110,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, | ... | @@ -110,7 +110,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, |
| 110 | }, | 110 | }, |
| 111 | State.Integer => switch (c) { | 111 | State.Integer => switch (c) { |
| 112 | '}' => { | 112 | '}' => { |
| 113 | try formatInt(args[next_arg], radix, uppercase, width, context, output); | 113 | try formatInt(args[next_arg], radix, uppercase, width, context, Errors, output); |
| 114 | next_arg += 1; | 114 | next_arg += 1; |
| 115 | state = State.Start; | 115 | state = State.Start; |
| 116 | start_index = i + 1; | 116 | start_index = i + 1; |
| ... | @@ -124,7 +124,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, | ... | @@ -124,7 +124,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, |
| 124 | State.IntegerWidth => switch (c) { | 124 | State.IntegerWidth => switch (c) { |
| 125 | '}' => { | 125 | '}' => { |
| 126 | width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable); | 126 | width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable); |
| 127 | try formatInt(args[next_arg], radix, uppercase, width, context, output); | 127 | try formatInt(args[next_arg], radix, uppercase, width, context, Errors, output); |
| 128 | next_arg += 1; | 128 | next_arg += 1; |
| 129 | state = State.Start; | 129 | state = State.Start; |
| 130 | start_index = i + 1; | 130 | start_index = i + 1; |
| ... | @@ -134,7 +134,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, | ... | @@ -134,7 +134,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, |
| 134 | }, | 134 | }, |
| 135 | State.Float => switch (c) { | 135 | State.Float => switch (c) { |
| 136 | '}' => { | 136 | '}' => { |
| 137 | try formatFloatDecimal(args[next_arg], 0, context, output); | 137 | try formatFloatDecimal(args[next_arg], 0, context, Errors, output); |
| 138 | next_arg += 1; | 138 | next_arg += 1; |
| 139 | state = State.Start; | 139 | state = State.Start; |
| 140 | start_index = i + 1; | 140 | start_index = i + 1; |
| ... | @@ -148,7 +148,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, | ... | @@ -148,7 +148,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, |
| 148 | State.FloatWidth => switch (c) { | 148 | State.FloatWidth => switch (c) { |
| 149 | '}' => { | 149 | '}' => { |
| 150 | width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable); | 150 | width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable); |
| 151 | try formatFloatDecimal(args[next_arg], width, context, output); | 151 | try formatFloatDecimal(args[next_arg], width, context, Errors, output); |
| 152 | next_arg += 1; | 152 | next_arg += 1; |
| 153 | state = State.Start; | 153 | state = State.Start; |
| 154 | start_index = i + 1; | 154 | start_index = i + 1; |
| ... | @@ -159,7 +159,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, | ... | @@ -159,7 +159,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, |
| 159 | State.BufWidth => switch (c) { | 159 | State.BufWidth => switch (c) { |
| 160 | '}' => { | 160 | '}' => { |
| 161 | width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable); | 161 | width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable); |
| 162 | try formatBuf(args[next_arg], width, context, output); | 162 | try formatBuf(args[next_arg], width, context, Errors, output); |
| 163 | next_arg += 1; | 163 | next_arg += 1; |
| 164 | state = State.Start; | 164 | state = State.Start; |
| 165 | start_index = i + 1; | 165 | start_index = i + 1; |
| ... | @@ -169,7 +169,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, | ... | @@ -169,7 +169,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, |
| 169 | }, | 169 | }, |
| 170 | State.Character => switch (c) { | 170 | State.Character => switch (c) { |
| 171 | '}' => { | 171 | '}' => { |
| 172 | try formatAsciiChar(args[next_arg], context, output); | 172 | try formatAsciiChar(args[next_arg], context, Errors, output); |
| 173 | next_arg += 1; | 173 | next_arg += 1; |
| 174 | state = State.Start; | 174 | state = State.Start; |
| 175 | start_index = i + 1; | 175 | start_index = i + 1; |
| ... | @@ -191,14 +191,14 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, | ... | @@ -191,14 +191,14 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)%void, |
| 191 | } | 191 | } |
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []const u8)%void) %void { | 194 | pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void { |
| 195 | const T = @typeOf(value); | 195 | const T = @typeOf(value); |
| 196 | switch (@typeId(T)) { | 196 | switch (@typeId(T)) { |
| 197 | builtin.TypeId.Int => { | 197 | builtin.TypeId.Int => { |
| 198 | return formatInt(value, 10, false, 0, context, output); | 198 | return formatInt(value, 10, false, 0, context, Errors, output); |
| 199 | }, | 199 | }, |
| 200 | builtin.TypeId.Float => { | 200 | builtin.TypeId.Float => { |
| 201 | return formatFloat(value, context, output); | 201 | return formatFloat(value, context, Errors, output); |
| 202 | }, | 202 | }, |
| 203 | builtin.TypeId.Void => { | 203 | builtin.TypeId.Void => { |
| 204 | return output(context, "void"); | 204 | return output(context, "void"); |
| ... | @@ -208,19 +208,19 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons | ... | @@ -208,19 +208,19 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons |
| 208 | }, | 208 | }, |
| 209 | builtin.TypeId.Nullable => { | 209 | builtin.TypeId.Nullable => { |
| 210 | if (value) |payload| { | 210 | if (value) |payload| { |
| 211 | return formatValue(payload, context, output); | 211 | return formatValue(payload, context, Errors, output); |
| 212 | } else { | 212 | } else { |
| 213 | return output(context, "null"); | 213 | return output(context, "null"); |
| 214 | } | 214 | } |
| 215 | }, | 215 | }, |
| 216 | builtin.TypeId.ErrorUnion => { | 216 | builtin.TypeId.ErrorUnion => { |
| 217 | if (value) |payload| { | 217 | if (value) |payload| { |
| 218 | return formatValue(payload, context, output); | 218 | return formatValue(payload, context, Errors, output); |
| 219 | } else |err| { | 219 | } else |err| { |
| 220 | return formatValue(err, context, output); | 220 | return formatValue(err, context, Errors, output); |
| 221 | } | 221 | } |
| 222 | }, | 222 | }, |
| 223 | builtin.TypeId.Error => { | 223 | builtin.TypeId.ErrorSet => { |
| 224 | try output(context, "error."); | 224 | try output(context, "error."); |
| 225 | return output(context, @errorName(value)); | 225 | return output(context, @errorName(value)); |
| 226 | }, | 226 | }, |
| ... | @@ -228,7 +228,7 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons | ... | @@ -228,7 +228,7 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons |
| 228 | if (@typeId(T.Child) == builtin.TypeId.Array and T.Child.Child == u8) { | 228 | if (@typeId(T.Child) == builtin.TypeId.Array and T.Child.Child == u8) { |
| 229 | return output(context, (*value)[0..]); | 229 | return output(context, (*value)[0..]); |
| 230 | } else { | 230 | } else { |
| 231 | return format(context, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)); | 231 | return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)); |
| 232 | } | 232 | } |
| 233 | }, | 233 | }, |
| 234 | else => if (@canImplicitCast([]const u8, value)) { | 234 | else => if (@canImplicitCast([]const u8, value)) { |
| ... | @@ -240,12 +240,12 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons | ... | @@ -240,12 +240,12 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons |
| 240 | } | 240 | } |
| 241 | } | 241 | } |
| 242 | 242 | ||
| 243 | pub fn formatAsciiChar(c: u8, context: var, output: fn(@typeOf(context), []const u8)%void) %void { | 243 | pub fn formatAsciiChar(c: u8, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void { |
| 244 | return output(context, (&c)[0..1]); | 244 | return output(context, (&c)[0..1]); |
| 245 | } | 245 | } |
| 246 | 246 | ||
| 247 | pub fn formatBuf(buf: []const u8, width: usize, | 247 | pub 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 |
| 249 | { | 249 | { |
| 250 | try output(context, buf); | 250 | try output(context, buf); |
| 251 | 251 | ||
| ... | @@ -256,7 +256,7 @@ pub fn formatBuf(buf: []const u8, width: usize, | ... | @@ -256,7 +256,7 @@ pub fn formatBuf(buf: []const u8, width: usize, |
| 256 | } | 256 | } |
| 257 | } | 257 | } |
| 258 | 258 | ||
| 259 | pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []const u8)%void) %void { | 259 | pub fn formatFloat(value: var, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void { |
| 260 | var x = f64(value); | 260 | var x = f64(value); |
| 261 | 261 | ||
| 262 | // Errol doesn't handle these special cases. | 262 | // Errol doesn't handle these special cases. |
| ... | @@ -290,11 +290,11 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons | ... | @@ -290,11 +290,11 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons |
| 290 | 290 | ||
| 291 | if (float_decimal.exp != 1) { | 291 | if (float_decimal.exp != 1) { |
| 292 | try output(context, "e"); | 292 | try output(context, "e"); |
| 293 | try formatInt(float_decimal.exp - 1, 10, false, 0, context, output); | 293 | try formatInt(float_decimal.exp - 1, 10, false, 0, context, Errors, output); |
| 294 | } | 294 | } |
| 295 | } | 295 | } |
| 296 | 296 | ||
| 297 | pub fn formatFloatDecimal(value: var, precision: usize, context: var, output: fn(@typeOf(context), []const u8)%void) %void { | 297 | pub fn formatFloatDecimal(value: var, precision: usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void { |
| 298 | var x = f64(value); | 298 | var x = f64(value); |
| 299 | 299 | ||
| 300 | // Errol doesn't handle these special cases. | 300 | // Errol doesn't handle these special cases. |
| ... | @@ -336,17 +336,17 @@ pub fn formatFloatDecimal(value: var, precision: usize, context: var, output: fn | ... | @@ -336,17 +336,17 @@ pub fn formatFloatDecimal(value: var, precision: usize, context: var, output: fn |
| 336 | 336 | ||
| 337 | 337 | ||
| 338 | pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize, | 338 | pub 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 |
| 340 | { | 340 | { |
| 341 | if (@typeOf(value).is_signed) { | 341 | if (@typeOf(value).is_signed) { |
| 342 | return formatIntSigned(value, base, uppercase, width, context, output); | 342 | return formatIntSigned(value, base, uppercase, width, context, Errors, output); |
| 343 | } else { | 343 | } else { |
| 344 | return formatIntUnsigned(value, base, uppercase, width, context, output); | 344 | return formatIntUnsigned(value, base, uppercase, width, context, Errors, output); |
| 345 | } | 345 | } |
| 346 | } | 346 | } |
| 347 | 347 | ||
| 348 | fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize, | 348 | fn 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 |
| 350 | { | 350 | { |
| 351 | const uint = @IntType(false, @typeOf(value).bit_count); | 351 | const uint = @IntType(false, @typeOf(value).bit_count); |
| 352 | if (value < 0) { | 352 | if (value < 0) { |
| ... | @@ -354,20 +354,20 @@ fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize, | ... | @@ -354,20 +354,20 @@ fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize, |
| 354 | try output(context, (&minus_sign)[0..1]); | 354 | try output(context, (&minus_sign)[0..1]); |
| 355 | const new_value = uint(-(value + 1)) + 1; | 355 | const new_value = uint(-(value + 1)) + 1; |
| 356 | const new_width = if (width == 0) 0 else (width - 1); | 356 | const new_width = if (width == 0) 0 else (width - 1); |
| 357 | return formatIntUnsigned(new_value, base, uppercase, new_width, context, output); | 357 | return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output); |
| 358 | } else if (width == 0) { | 358 | } else if (width == 0) { |
| 359 | return formatIntUnsigned(uint(value), base, uppercase, width, context, output); | 359 | return formatIntUnsigned(uint(value), base, uppercase, width, context, Errors, output); |
| 360 | } else { | 360 | } else { |
| 361 | const plus_sign: u8 = '+'; | 361 | const plus_sign: u8 = '+'; |
| 362 | try output(context, (&plus_sign)[0..1]); | 362 | try output(context, (&plus_sign)[0..1]); |
| 363 | const new_value = uint(value); | 363 | const new_value = uint(value); |
| 364 | const new_width = if (width == 0) 0 else (width - 1); | 364 | const new_width = if (width == 0) 0 else (width - 1); |
| 365 | return formatIntUnsigned(new_value, base, uppercase, new_width, context, output); | 365 | return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output); |
| 366 | } | 366 | } |
| 367 | } | 367 | } |
| 368 | 368 | ||
| 369 | fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize, | 369 | fn 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 |
| 371 | { | 371 | { |
| 372 | // max_int_digits accounts for the minus sign. when printing an unsigned | 372 | // max_int_digits accounts for the minus sign. when printing an unsigned |
| 373 | // number we don't need to do that. | 373 | // number we don't need to do that. |
| ... | @@ -410,19 +410,19 @@ pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width: | ... | @@ -410,19 +410,19 @@ pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width: |
| 410 | .out_buf = out_buf, | 410 | .out_buf = out_buf, |
| 411 | .index = 0, | 411 | .index = 0, |
| 412 | }; | 412 | }; |
| 413 | formatInt(value, base, uppercase, width, &context, formatIntCallback) catch unreachable; | 413 | formatInt(value, base, uppercase, width, &context, error{}, formatIntCallback) catch unreachable; |
| 414 | return context.index; | 414 | return context.index; |
| 415 | } | 415 | } |
| 416 | const FormatIntBuf = struct { | 416 | const FormatIntBuf = struct { |
| 417 | out_buf: []u8, | 417 | out_buf: []u8, |
| 418 | index: usize, | 418 | index: usize, |
| 419 | }; | 419 | }; |
| 420 | fn formatIntCallback(context: &FormatIntBuf, bytes: []const u8) %void { | 420 | fn formatIntCallback(context: &FormatIntBuf, bytes: []const u8) (error{}!void) { |
| 421 | mem.copy(u8, context.out_buf[context.index..], bytes); | 421 | mem.copy(u8, context.out_buf[context.index..], bytes); |
| 422 | context.index += bytes.len; | 422 | context.index += bytes.len; |
| 423 | } | 423 | } |
| 424 | 424 | ||
| 425 | pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) %T { | 425 | pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T { |
| 426 | if (!T.is_signed) | 426 | if (!T.is_signed) |
| 427 | return parseUnsigned(T, buf, radix); | 427 | return parseUnsigned(T, buf, radix); |
| 428 | if (buf.len == 0) | 428 | if (buf.len == 0) |
| ... | @@ -439,14 +439,21 @@ pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) %T { | ... | @@ -439,14 +439,21 @@ pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) %T { |
| 439 | test "fmt.parseInt" { | 439 | test "fmt.parseInt" { |
| 440 | assert((parseInt(i32, "-10", 10) catch unreachable) == -10); | 440 | assert((parseInt(i32, "-10", 10) catch unreachable) == -10); |
| 441 | assert((parseInt(i32, "+10", 10) catch unreachable) == 10); | 441 | assert((parseInt(i32, "+10", 10) catch unreachable) == 10); |
| 442 | assert(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidChar); | 442 | assert(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter); |
| 443 | assert(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidChar); | 443 | assert(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter); |
| 444 | assert(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidChar); | 444 | assert(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter); |
| 445 | assert((parseInt(u8, "255", 10) catch unreachable) == 255); | 445 | assert((parseInt(u8, "255", 10) catch unreachable) == 255); |
| 446 | assert(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow); | 446 | assert(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow); |
| 447 | } | 447 | } |
| 448 | 448 | ||
| 449 | pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) %T { | 449 | const 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 | |||
| 456 | pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsignedError!T { | ||
| 450 | var x: T = 0; | 457 | var x: T = 0; |
| 451 | 458 | ||
| 452 | for (buf) |c| { | 459 | for (buf) |c| { |
| ... | @@ -458,17 +465,16 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) %T { | ... | @@ -458,17 +465,16 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) %T { |
| 458 | return x; | 465 | return x; |
| 459 | } | 466 | } |
| 460 | 467 | ||
| 461 | error InvalidChar; | 468 | fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) { |
| 462 | fn charToDigit(c: u8, radix: u8) %u8 { | ||
| 463 | const value = switch (c) { | 469 | const value = switch (c) { |
| 464 | '0' ... '9' => c - '0', | 470 | '0' ... '9' => c - '0', |
| 465 | 'A' ... 'Z' => c - 'A' + 10, | 471 | 'A' ... 'Z' => c - 'A' + 10, |
| 466 | 'a' ... 'z' => c - 'a' + 10, | 472 | 'a' ... 'z' => c - 'a' + 10, |
| 467 | else => return error.InvalidChar, | 473 | else => return error.InvalidCharacter, |
| 468 | }; | 474 | }; |
| 469 | 475 | ||
| 470 | if (value >= radix) | 476 | if (value >= radix) |
| 471 | return error.InvalidChar; | 477 | return error.InvalidCharacter; |
| 472 | 478 | ||
| 473 | return value; | 479 | return value; |
| 474 | } | 480 | } |
| ... | @@ -485,28 +491,26 @@ const BufPrintContext = struct { | ... | @@ -485,28 +491,26 @@ const BufPrintContext = struct { |
| 485 | remaining: []u8, | 491 | remaining: []u8, |
| 486 | }; | 492 | }; |
| 487 | 493 | ||
| 488 | error BufferTooSmall; | 494 | fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) !void { |
| 489 | fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) %void { | ||
| 490 | if (context.remaining.len < bytes.len) return error.BufferTooSmall; | 495 | if (context.remaining.len < bytes.len) return error.BufferTooSmall; |
| 491 | mem.copy(u8, context.remaining, bytes); | 496 | mem.copy(u8, context.remaining, bytes); |
| 492 | context.remaining = context.remaining[bytes.len..]; | 497 | context.remaining = context.remaining[bytes.len..]; |
| 493 | } | 498 | } |
| 494 | 499 | ||
| 495 | pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) %[]u8 { | 500 | pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 { |
| 496 | var context = BufPrintContext { .remaining = buf, }; | 501 | var context = BufPrintContext { .remaining = buf, }; |
| 497 | try format(&context, bufPrintWrite, fmt, args); | 502 | try format(&context, error{BufferTooSmall}, bufPrintWrite, fmt, args); |
| 498 | return buf[0..buf.len - context.remaining.len]; | 503 | return buf[0..buf.len - context.remaining.len]; |
| 499 | } | 504 | } |
| 500 | 505 | ||
| 501 | pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...) %[]u8 { | 506 | pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...) ![]u8 { |
| 502 | var size: usize = 0; | 507 | var size: usize = 0; |
| 503 | // Cannot fail because `countSize` cannot fail. | 508 | format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {}; |
| 504 | format(&size, countSize, fmt, args) catch unreachable; | ||
| 505 | const buf = try allocator.alloc(u8, size); | 509 | const buf = try allocator.alloc(u8, size); |
| 506 | return bufPrint(buf, fmt, args); | 510 | return bufPrint(buf, fmt, args); |
| 507 | } | 511 | } |
| 508 | 512 | ||
| 509 | fn countSize(size: &usize, bytes: []const u8) %void { | 513 | fn countSize(size: &usize, bytes: []const u8) (error{}!void) { |
| 510 | *size += bytes.len; | 514 | *size += bytes.len; |
| 511 | } | 515 | } |
| 512 | 516 | ||
| ... | @@ -534,7 +538,7 @@ fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, width: u | ... | @@ -534,7 +538,7 @@ fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, width: u |
| 534 | 538 | ||
| 535 | test "parse u64 digit too big" { | 539 | test "parse u64 digit too big" { |
| 536 | _ = parseUnsigned(u64, "123a", 10) catch |err| { | 540 | _ = parseUnsigned(u64, "123a", 10) catch |err| { |
| 537 | if (err == error.InvalidChar) return; | 541 | if (err == error.InvalidCharacter) return; |
| 538 | unreachable; | 542 | unreachable; |
| 539 | }; | 543 | }; |
| 540 | unreachable; | 544 | unreachable; |
| ... | @@ -567,13 +571,13 @@ test "fmt.format" { | ... | @@ -567,13 +571,13 @@ test "fmt.format" { |
| 567 | } | 571 | } |
| 568 | { | 572 | { |
| 569 | var buf1: [32]u8 = undefined; | 573 | var buf1: [32]u8 = undefined; |
| 570 | const value: %i32 = 1234; | 574 | const value: error!i32 = 1234; |
| 571 | const result = try bufPrint(buf1[0..], "error union: {}\n", value); | 575 | const result = try bufPrint(buf1[0..], "error union: {}\n", value); |
| 572 | assert(mem.eql(u8, result, "error union: 1234\n")); | 576 | assert(mem.eql(u8, result, "error union: 1234\n")); |
| 573 | } | 577 | } |
| 574 | { | 578 | { |
| 575 | var buf1: [32]u8 = undefined; | 579 | var buf1: [32]u8 = undefined; |
| 576 | const value: %i32 = error.InvalidChar; | 580 | const value: error!i32 = error.InvalidChar; |
| 577 | const result = try bufPrint(buf1[0..], "error union: {}\n", value); | 581 | const result = try bufPrint(buf1[0..], "error union: {}\n", value); |
| 578 | assert(mem.eql(u8, result, "error union: error.InvalidChar\n")); | 582 | assert(mem.eql(u8, result, "error union: error.InvalidChar\n")); |
| 579 | } | 583 | } |
std/hash_map.zig+2-2| ... | @@ -80,7 +80,7 @@ pub fn HashMap(comptime K: type, comptime V: type, | ... | @@ -80,7 +80,7 @@ pub fn HashMap(comptime K: type, comptime V: type, |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | /// Returns the value that was already there. | 82 | /// Returns the value that was already there. |
| 83 | pub fn put(hm: &Self, key: K, value: &const V) %?V { | 83 | pub fn put(hm: &Self, key: K, value: &const V) !?V { |
| 84 | if (hm.entries.len == 0) { | 84 | if (hm.entries.len == 0) { |
| 85 | try hm.initCapacity(16); | 85 | try hm.initCapacity(16); |
| 86 | } | 86 | } |
| ... | @@ -151,7 +151,7 @@ pub fn HashMap(comptime K: type, comptime V: type, | ... | @@ -151,7 +151,7 @@ pub fn HashMap(comptime K: type, comptime V: type, |
| 151 | }; | 151 | }; |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | fn initCapacity(hm: &Self, capacity: usize) %void { | 154 | fn initCapacity(hm: &Self, capacity: usize) !void { |
| 155 | hm.entries = try hm.allocator.alloc(Entry, capacity); | 155 | hm.entries = try hm.allocator.alloc(Entry, capacity); |
| 156 | hm.size = 0; | 156 | hm.size = 0; |
| 157 | hm.max_distance_from_start_index = 0; | 157 | hm.max_distance_from_start_index = 0; |
std/heap.zig+5-7| ... | @@ -9,8 +9,6 @@ const c = std.c; | ... | @@ -9,8 +9,6 @@ const c = std.c; |
| 9 | 9 | ||
| 10 | const Allocator = mem.Allocator; | 10 | const Allocator = mem.Allocator; |
| 11 | 11 | ||
| 12 | error OutOfMemory; | ||
| 13 | |||
| 14 | pub const c_allocator = &c_allocator_state; | 12 | pub const c_allocator = &c_allocator_state; |
| 15 | var c_allocator_state = Allocator { | 13 | var c_allocator_state = Allocator { |
| 16 | .allocFn = cAlloc, | 14 | .allocFn = cAlloc, |
| ... | @@ -18,14 +16,14 @@ var c_allocator_state = Allocator { | ... | @@ -18,14 +16,14 @@ var c_allocator_state = Allocator { |
| 18 | .freeFn = cFree, | 16 | .freeFn = cFree, |
| 19 | }; | 17 | }; |
| 20 | 18 | ||
| 21 | fn cAlloc(self: &Allocator, n: usize, alignment: u29) %[]u8 { | 19 | fn cAlloc(self: &Allocator, n: usize, alignment: u29) ![]u8 { |
| 22 | return if (c.malloc(usize(n))) |buf| | 20 | return if (c.malloc(usize(n))) |buf| |
| 23 | @ptrCast(&u8, buf)[0..n] | 21 | @ptrCast(&u8, buf)[0..n] |
| 24 | else | 22 | else |
| 25 | error.OutOfMemory; | 23 | error.OutOfMemory; |
| 26 | } | 24 | } |
| 27 | 25 | ||
| 28 | fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) %[]u8 { | 26 | fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 { |
| 29 | const old_ptr = @ptrCast(&c_void, old_mem.ptr); | 27 | const old_ptr = @ptrCast(&c_void, old_mem.ptr); |
| 30 | if (c.realloc(old_ptr, new_size)) |buf| { | 28 | if (c.realloc(old_ptr, new_size)) |buf| { |
| 31 | return @ptrCast(&u8, buf)[0..new_size]; | 29 | return @ptrCast(&u8, buf)[0..new_size]; |
| ... | @@ -47,7 +45,7 @@ pub const IncrementingAllocator = struct { | ... | @@ -47,7 +45,7 @@ pub const IncrementingAllocator = struct { |
| 47 | end_index: usize, | 45 | end_index: usize, |
| 48 | heap_handle: if (builtin.os == Os.windows) os.windows.HANDLE else void, | 46 | heap_handle: if (builtin.os == Os.windows) os.windows.HANDLE else void, |
| 49 | 47 | ||
| 50 | fn init(capacity: usize) %IncrementingAllocator { | 48 | fn init(capacity: usize) !IncrementingAllocator { |
| 51 | switch (builtin.os) { | 49 | switch (builtin.os) { |
| 52 | Os.linux, Os.macosx, Os.ios => { | 50 | Os.linux, Os.macosx, Os.ios => { |
| 53 | const p = os.posix; | 51 | const p = os.posix; |
| ... | @@ -105,7 +103,7 @@ pub const IncrementingAllocator = struct { | ... | @@ -105,7 +103,7 @@ pub const IncrementingAllocator = struct { |
| 105 | return self.bytes.len - self.end_index; | 103 | return self.bytes.len - self.end_index; |
| 106 | } | 104 | } |
| 107 | 105 | ||
| 108 | fn alloc(allocator: &Allocator, n: usize, alignment: u29) %[]u8 { | 106 | fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 { |
| 109 | const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator); | 107 | const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator); |
| 110 | const addr = @ptrToInt(&self.bytes[self.end_index]); | 108 | const addr = @ptrToInt(&self.bytes[self.end_index]); |
| 111 | const rem = @rem(addr, alignment); | 109 | const rem = @rem(addr, alignment); |
| ... | @@ -120,7 +118,7 @@ pub const IncrementingAllocator = struct { | ... | @@ -120,7 +118,7 @@ pub const IncrementingAllocator = struct { |
| 120 | return result; | 118 | return result; |
| 121 | } | 119 | } |
| 122 | 120 | ||
| 123 | fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) %[]u8 { | 121 | fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 { |
| 124 | if (new_size <= old_mem.len) { | 122 | if (new_size <= old_mem.len) { |
| 125 | return old_mem[0..new_size]; | 123 | return old_mem[0..new_size]; |
| 126 | } else { | 124 | } else { |
std/io.zig+195-193| ... | @@ -26,31 +26,9 @@ test "import io tests" { | ... | @@ -26,31 +26,9 @@ test "import io tests" { |
| 26 | } | 26 | } |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | /// The function received invalid input at runtime. An Invalid error means a | 29 | const GetStdIoErrs = os.WindowsGetStdHandleErrs; |
| 30 | /// bug in the program that called the function. | 30 | |
| 31 | error Invalid; | 31 | pub fn getStdErr() GetStdIoErrs!File { |
| 32 | |||
| 33 | error DiskQuota; | ||
| 34 | error FileTooBig; | ||
| 35 | error Io; | ||
| 36 | error NoSpaceLeft; | ||
| 37 | error BadPerm; | ||
| 38 | error BrokenPipe; | ||
| 39 | error BadFd; | ||
| 40 | error IsDir; | ||
| 41 | error NotDir; | ||
| 42 | error SymLinkLoop; | ||
| 43 | error ProcessFdQuotaExceeded; | ||
| 44 | error SystemFdQuotaExceeded; | ||
| 45 | error NameTooLong; | ||
| 46 | error NoDevice; | ||
| 47 | error PathNotFound; | ||
| 48 | error OutOfMemory; | ||
| 49 | error Unseekable; | ||
| 50 | error EndOfFile; | ||
| 51 | error FilePosLargerThanPointerRange; | ||
| 52 | |||
| 53 | pub fn getStdErr() %File { | ||
| 54 | const handle = if (is_windows) | 32 | const handle = if (is_windows) |
| 55 | try os.windowsGetStdHandle(system.STD_ERROR_HANDLE) | 33 | try os.windowsGetStdHandle(system.STD_ERROR_HANDLE) |
| 56 | else if (is_posix) | 34 | else if (is_posix) |
| ... | @@ -60,7 +38,7 @@ pub fn getStdErr() %File { | ... | @@ -60,7 +38,7 @@ pub fn getStdErr() %File { |
| 60 | return File.openHandle(handle); | 38 | return File.openHandle(handle); |
| 61 | } | 39 | } |
| 62 | 40 | ||
| 63 | pub fn getStdOut() %File { | 41 | pub fn getStdOut() GetStdIoErrs!File { |
| 64 | const handle = if (is_windows) | 42 | const handle = if (is_windows) |
| 65 | try os.windowsGetStdHandle(system.STD_OUTPUT_HANDLE) | 43 | try os.windowsGetStdHandle(system.STD_OUTPUT_HANDLE) |
| 66 | else if (is_posix) | 44 | else if (is_posix) |
| ... | @@ -70,7 +48,7 @@ pub fn getStdOut() %File { | ... | @@ -70,7 +48,7 @@ pub fn getStdOut() %File { |
| 70 | return File.openHandle(handle); | 48 | return File.openHandle(handle); |
| 71 | } | 49 | } |
| 72 | 50 | ||
| 73 | pub fn getStdIn() %File { | 51 | pub fn getStdIn() GetStdIoErrs!File { |
| 74 | const handle = if (is_windows) | 52 | const handle = if (is_windows) |
| 75 | try os.windowsGetStdHandle(system.STD_INPUT_HANDLE) | 53 | try os.windowsGetStdHandle(system.STD_INPUT_HANDLE) |
| 76 | else if (is_posix) | 54 | else if (is_posix) |
| ... | @@ -83,18 +61,21 @@ pub fn getStdIn() %File { | ... | @@ -83,18 +61,21 @@ pub fn getStdIn() %File { |
| 83 | /// Implementation of InStream trait for File | 61 | /// Implementation of InStream trait for File |
| 84 | pub const FileInStream = struct { | 62 | pub const FileInStream = struct { |
| 85 | file: &File, | 63 | file: &File, |
| 86 | stream: InStream, | 64 | stream: Stream, |
| 65 | |||
| 66 | pub const Error = @typeOf(File.read).ReturnType.ErrorSet; | ||
| 67 | pub const Stream = InStream(Error); | ||
| 87 | 68 | ||
| 88 | pub fn init(file: &File) FileInStream { | 69 | pub fn init(file: &File) FileInStream { |
| 89 | return FileInStream { | 70 | return FileInStream { |
| 90 | .file = file, | 71 | .file = file, |
| 91 | .stream = InStream { | 72 | .stream = Stream { |
| 92 | .readFn = readFn, | 73 | .readFn = readFn, |
| 93 | }, | 74 | }, |
| 94 | }; | 75 | }; |
| 95 | } | 76 | } |
| 96 | 77 | ||
| 97 | fn readFn(in_stream: &InStream, buffer: []u8) %usize { | 78 | fn readFn(in_stream: &Stream, buffer: []u8) Error!usize { |
| 98 | const self = @fieldParentPtr(FileInStream, "stream", in_stream); | 79 | const self = @fieldParentPtr(FileInStream, "stream", in_stream); |
| 99 | return self.file.read(buffer); | 80 | return self.file.read(buffer); |
| 100 | } | 81 | } |
| ... | @@ -103,18 +84,21 @@ pub const FileInStream = struct { | ... | @@ -103,18 +84,21 @@ pub const FileInStream = struct { |
| 103 | /// Implementation of OutStream trait for File | 84 | /// Implementation of OutStream trait for File |
| 104 | pub const FileOutStream = struct { | 85 | pub const FileOutStream = struct { |
| 105 | file: &File, | 86 | file: &File, |
| 106 | stream: OutStream, | 87 | stream: Stream, |
| 88 | |||
| 89 | pub const Error = File.WriteError; | ||
| 90 | pub const Stream = OutStream(Error); | ||
| 107 | 91 | ||
| 108 | pub fn init(file: &File) FileOutStream { | 92 | pub fn init(file: &File) FileOutStream { |
| 109 | return FileOutStream { | 93 | return FileOutStream { |
| 110 | .file = file, | 94 | .file = file, |
| 111 | .stream = OutStream { | 95 | .stream = Stream { |
| 112 | .writeFn = writeFn, | 96 | .writeFn = writeFn, |
| 113 | }, | 97 | }, |
| 114 | }; | 98 | }; |
| 115 | } | 99 | } |
| 116 | 100 | ||
| 117 | fn writeFn(out_stream: &OutStream, bytes: []const u8) %void { | 101 | fn writeFn(out_stream: &Stream, bytes: []const u8) !void { |
| 118 | const self = @fieldParentPtr(FileOutStream, "stream", out_stream); | 102 | const self = @fieldParentPtr(FileOutStream, "stream", out_stream); |
| 119 | return self.file.write(bytes); | 103 | return self.file.write(bytes); |
| 120 | } | 104 | } |
| ... | @@ -124,12 +108,14 @@ pub const File = struct { | ... | @@ -124,12 +108,14 @@ pub const File = struct { |
| 124 | /// The OS-specific file descriptor or file handle. | 108 | /// The OS-specific file descriptor or file handle. |
| 125 | handle: os.FileHandle, | 109 | handle: os.FileHandle, |
| 126 | 110 | ||
| 111 | const OpenError = os.WindowsOpenError || os.PosixOpenError; | ||
| 112 | |||
| 127 | /// `path` may need to be copied in memory to add a null terminating byte. In this case | 113 | /// `path` may need to be copied in memory to add a null terminating byte. In this case |
| 128 | /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed | 114 | /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed |
| 129 | /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned. | 115 | /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned. |
| 130 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. | 116 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. |
| 131 | /// Call close to clean up. | 117 | /// Call close to clean up. |
| 132 | pub fn openRead(path: []const u8, allocator: ?&mem.Allocator) %File { | 118 | pub fn openRead(path: []const u8, allocator: ?&mem.Allocator) OpenError!File { |
| 133 | if (is_posix) { | 119 | if (is_posix) { |
| 134 | const flags = system.O_LARGEFILE|system.O_RDONLY; | 120 | const flags = system.O_LARGEFILE|system.O_RDONLY; |
| 135 | const fd = try os.posixOpen(path, flags, 0, allocator); | 121 | const fd = try os.posixOpen(path, flags, 0, allocator); |
| ... | @@ -144,7 +130,7 @@ pub const File = struct { | ... | @@ -144,7 +130,7 @@ pub const File = struct { |
| 144 | } | 130 | } |
| 145 | 131 | ||
| 146 | /// Calls `openWriteMode` with 0o666 for the mode. | 132 | /// Calls `openWriteMode` with 0o666 for the mode. |
| 147 | pub fn openWrite(path: []const u8, allocator: ?&mem.Allocator) %File { | 133 | pub fn openWrite(path: []const u8, allocator: ?&mem.Allocator) !File { |
| 148 | return openWriteMode(path, 0o666, allocator); | 134 | return openWriteMode(path, 0o666, allocator); |
| 149 | 135 | ||
| 150 | } | 136 | } |
| ... | @@ -154,7 +140,7 @@ pub const File = struct { | ... | @@ -154,7 +140,7 @@ pub const File = struct { |
| 154 | /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned. | 140 | /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned. |
| 155 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. | 141 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. |
| 156 | /// Call close to clean up. | 142 | /// Call close to clean up. |
| 157 | pub fn openWriteMode(path: []const u8, mode: usize, allocator: ?&mem.Allocator) %File { | 143 | pub fn openWriteMode(path: []const u8, mode: usize, allocator: ?&mem.Allocator) !File { |
| 158 | if (is_posix) { | 144 | if (is_posix) { |
| 159 | const flags = system.O_LARGEFILE|system.O_WRONLY|system.O_CREAT|system.O_CLOEXEC|system.O_TRUNC; | 145 | const flags = system.O_LARGEFILE|system.O_WRONLY|system.O_CREAT|system.O_CLOEXEC|system.O_TRUNC; |
| 160 | const fd = try os.posixOpen(path, flags, mode, allocator); | 146 | const fd = try os.posixOpen(path, flags, mode, allocator); |
| ... | @@ -189,7 +175,7 @@ pub const File = struct { | ... | @@ -189,7 +175,7 @@ pub const File = struct { |
| 189 | return os.isTty(self.handle); | 175 | return os.isTty(self.handle); |
| 190 | } | 176 | } |
| 191 | 177 | ||
| 192 | pub fn seekForward(self: &File, amount: isize) %void { | 178 | pub fn seekForward(self: &File, amount: isize) !void { |
| 193 | switch (builtin.os) { | 179 | switch (builtin.os) { |
| 194 | Os.linux, Os.macosx, Os.ios => { | 180 | Os.linux, Os.macosx, Os.ios => { |
| 195 | const result = system.lseek(self.handle, amount, system.SEEK_CUR); | 181 | const result = system.lseek(self.handle, amount, system.SEEK_CUR); |
| ... | @@ -218,7 +204,7 @@ pub const File = struct { | ... | @@ -218,7 +204,7 @@ pub const File = struct { |
| 218 | } | 204 | } |
| 219 | } | 205 | } |
| 220 | 206 | ||
| 221 | pub fn seekTo(self: &File, pos: usize) %void { | 207 | pub fn seekTo(self: &File, pos: usize) !void { |
| 222 | switch (builtin.os) { | 208 | switch (builtin.os) { |
| 223 | Os.linux, Os.macosx, Os.ios => { | 209 | Os.linux, Os.macosx, Os.ios => { |
| 224 | const ipos = try math.cast(isize, pos); | 210 | const ipos = try math.cast(isize, pos); |
| ... | @@ -249,7 +235,7 @@ pub const File = struct { | ... | @@ -249,7 +235,7 @@ pub const File = struct { |
| 249 | } | 235 | } |
| 250 | } | 236 | } |
| 251 | 237 | ||
| 252 | pub fn getPos(self: &File) %usize { | 238 | pub fn getPos(self: &File) !usize { |
| 253 | switch (builtin.os) { | 239 | switch (builtin.os) { |
| 254 | Os.linux, Os.macosx, Os.ios => { | 240 | Os.linux, Os.macosx, Os.ios => { |
| 255 | const result = system.lseek(self.handle, 0, system.SEEK_CUR); | 241 | const result = system.lseek(self.handle, 0, system.SEEK_CUR); |
| ... | @@ -289,7 +275,7 @@ pub const File = struct { | ... | @@ -289,7 +275,7 @@ pub const File = struct { |
| 289 | } | 275 | } |
| 290 | } | 276 | } |
| 291 | 277 | ||
| 292 | pub fn getEndPos(self: &File) %usize { | 278 | pub fn getEndPos(self: &File) !usize { |
| 293 | if (is_posix) { | 279 | if (is_posix) { |
| 294 | var stat: system.Stat = undefined; | 280 | var stat: system.Stat = undefined; |
| 295 | const err = system.getErrno(system.fstat(self.handle, &stat)); | 281 | const err = system.getErrno(system.fstat(self.handle, &stat)); |
| ... | @@ -318,7 +304,9 @@ pub const File = struct { | ... | @@ -318,7 +304,9 @@ pub const File = struct { |
| 318 | } | 304 | } |
| 319 | } | 305 | } |
| 320 | 306 | ||
| 321 | pub fn read(self: &File, buffer: []u8) %usize { | 307 | pub const ReadError = error {}; |
| 308 | |||
| 309 | pub fn read(self: &File, buffer: []u8) !usize { | ||
| 322 | if (is_posix) { | 310 | if (is_posix) { |
| 323 | var index: usize = 0; | 311 | var index: usize = 0; |
| 324 | while (index < buffer.len) { | 312 | while (index < buffer.len) { |
| ... | @@ -360,7 +348,9 @@ pub const File = struct { | ... | @@ -360,7 +348,9 @@ pub const File = struct { |
| 360 | } | 348 | } |
| 361 | } | 349 | } |
| 362 | 350 | ||
| 363 | fn write(self: &File, bytes: []const u8) %void { | 351 | pub const WriteError = os.WindowsWriteError || os.PosixWriteError; |
| 352 | |||
| 353 | fn write(self: &File, bytes: []const u8) WriteError!void { | ||
| 364 | if (is_posix) { | 354 | if (is_posix) { |
| 365 | try os.posixWrite(self.handle, bytes); | 355 | try os.posixWrite(self.handle, bytes); |
| 366 | } else if (is_windows) { | 356 | } else if (is_windows) { |
| ... | @@ -371,180 +361,183 @@ pub const File = struct { | ... | @@ -371,180 +361,183 @@ pub const File = struct { |
| 371 | } | 361 | } |
| 372 | }; | 362 | }; |
| 373 | 363 | ||
| 374 | error StreamTooLong; | 364 | pub fn InStream(comptime Error: type) type { |
| 375 | error EndOfStream; | 365 | return struct { |
| 376 | 366 | const Self = this; | |
| 377 | pub 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 | } | ||
| 406 | 367 | ||
| 407 | /// Allocates enough memory to hold all the contents of the stream. If the allocated | 368 | /// Return the number of bytes read. If the number read is smaller than buf.len, it |
| 408 | /// memory would be greater than `max_size`, returns `error.StreamTooLong`. | 369 | /// means the stream reached the end. Reaching the end of a stream is not an error |
| 409 | /// Caller owns returned memory. | 370 | /// condition. |
| 410 | /// If this function returns an error, the contents from the stream read so far are lost. | 371 | readFn: fn(self: &Self, buffer: []u8) Error!usize, |
| 411 | pub fn readAllAlloc(self: &InStream, allocator: &mem.Allocator, max_size: usize) %[]u8 { | ||
| 412 | var buf = Buffer.initNull(allocator); | ||
| 413 | defer buf.deinit(); | ||
| 414 | 372 | ||
| 415 | try self.readAllBuffer(&buf, max_size); | 373 | /// Replaces `buffer` contents by reading from the stream until it is finished. |
| 416 | return buf.toOwnedSlice(); | 374 | /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and |
| 417 | } | 375 | /// the contents read from the stream are lost. |
| 376 | pub fn readAllBuffer(self: &Self, buffer: &Buffer, max_size: usize) !void { | ||
| 377 | try buffer.resize(0); | ||
| 418 | 378 | ||
| 419 | /// Replaces `buffer` contents by reading from the stream until `delimiter` is found. | 379 | var actual_buf_len: usize = 0; |
| 420 | /// Does not include the delimiter in the result. | 380 | while (true) { |
| 421 | /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents | 381 | const dest_slice = buffer.toSlice()[actual_buf_len..]; |
| 422 | /// read from the stream so far are lost. | 382 | const bytes_read = try self.readFn(self, dest_slice); |
| 423 | pub fn readUntilDelimiterBuffer(self: &InStream, buffer: &Buffer, delimiter: u8, max_size: usize) %void { | 383 | actual_buf_len += bytes_read; |
| 424 | try buf.resize(0); | ||
| 425 | 384 | ||
| 426 | while (true) { | 385 | if (bytes_read != dest_slice.len) { |
| 427 | var byte: u8 = try self.readByte(); | 386 | buffer.shrink(actual_buf_len); |
| 387 | return; | ||
| 388 | } | ||
| 428 | 389 | ||
| 429 | if (byte == delimiter) { | 390 | const new_buf_size = math.min(max_size, actual_buf_len + os.page_size); |
| 430 | return; | 391 | if (new_buf_size == actual_buf_len) |
| 392 | return error.StreamTooLong; | ||
| 393 | try buffer.resize(new_buf_size); | ||
| 431 | } | 394 | } |
| 395 | } | ||
| 432 | 396 | ||
| 433 | if (buf.len() == max_size) { | 397 | /// Allocates enough memory to hold all the contents of the stream. If the allocated |
| 434 | return error.StreamTooLong; | 398 | /// memory would be greater than `max_size`, returns `error.StreamTooLong`. |
| 435 | } | 399 | /// Caller owns returned memory. |
| 400 | /// If this function returns an error, the contents from the stream read so far are lost. | ||
| 401 | pub fn readAllAlloc(self: &Self, allocator: &mem.Allocator, max_size: usize) ![]u8 { | ||
| 402 | var buf = Buffer.initNull(allocator); | ||
| 403 | defer buf.deinit(); | ||
| 436 | 404 | ||
| 437 | try buf.appendByte(byte); | 405 | try self.readAllBuffer(&buf, max_size); |
| 406 | return buf.toOwnedSlice(); | ||
| 438 | } | 407 | } |
| 439 | } | ||
| 440 | 408 | ||
| 441 | /// Allocates enough memory to read until `delimiter`. If the allocated | 409 | /// Replaces `buffer` contents by reading from the stream until `delimiter` is found. |
| 442 | /// memory would be greater than `max_size`, returns `error.StreamTooLong`. | 410 | /// Does not include the delimiter in the result. |
| 443 | /// Caller owns returned memory. | 411 | /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents |
| 444 | /// If this function returns an error, the contents from the stream read so far are lost. | 412 | /// read from the stream so far are lost. |
| 445 | pub fn readUntilDelimiterAlloc(self: &InStream, allocator: &mem.Allocator, | 413 | pub fn readUntilDelimiterBuffer(self: &Self, buffer: &Buffer, delimiter: u8, max_size: usize) !void { |
| 446 | delimiter: u8, max_size: usize) %[]u8 | 414 | try buf.resize(0); |
| 447 | { | ||
| 448 | var buf = Buffer.initNull(allocator); | ||
| 449 | defer buf.deinit(); | ||
| 450 | |||
| 451 | try self.readUntilDelimiterBuffer(self, &buf, delimiter, max_size); | ||
| 452 | return buf.toOwnedSlice(); | ||
| 453 | } | ||
| 454 | 415 | ||
| 455 | /// Returns the number of bytes read. If the number read is smaller than buf.len, it | 416 | while (true) { |
| 456 | /// means the stream reached the end. Reaching the end of a stream is not an error | 417 | var byte: u8 = try self.readByte(); |
| 457 | /// condition. | ||
| 458 | pub fn read(self: &InStream, buffer: []u8) %usize { | ||
| 459 | return self.readFn(self, buffer); | ||
| 460 | } | ||
| 461 | 418 | ||
| 462 | /// Same as `read` but end of stream returns `error.EndOfStream`. | 419 | if (byte == delimiter) { |
| 463 | pub fn readNoEof(self: &InStream, buf: []u8) %void { | 420 | return; |
| 464 | const amt_read = try self.read(buf); | 421 | } |
| 465 | if (amt_read < buf.len) return error.EndOfStream; | ||
| 466 | } | ||
| 467 | 422 | ||
| 468 | /// Reads 1 byte from the stream or returns `error.EndOfStream`. | 423 | if (buf.len() == max_size) { |
| 469 | pub fn readByte(self: &InStream) %u8 { | 424 | return error.StreamTooLong; |
| 470 | var result: [1]u8 = undefined; | 425 | } |
| 471 | try self.readNoEof(result[0..]); | ||
| 472 | return result[0]; | ||
| 473 | } | ||
| 474 | 426 | ||
| 475 | /// Same as `readByte` except the returned byte is signed. | 427 | try buf.appendByte(byte); |
| 476 | pub fn readByteSigned(self: &InStream) %i8 { | 428 | } |
| 477 | return @bitCast(i8, try self.readByte()); | 429 | } |
| 478 | } | ||
| 479 | 430 | ||
| 480 | pub fn readIntLe(self: &InStream, comptime T: type) %T { | 431 | /// Allocates enough memory to read until `delimiter`. If the allocated |
| 481 | return self.readInt(builtin.Endian.Little, T); | 432 | /// memory would be greater than `max_size`, returns `error.StreamTooLong`. |
| 482 | } | 433 | /// Caller owns returned memory. |
| 434 | /// If this function returns an error, the contents from the stream read so far are lost. | ||
| 435 | pub fn readUntilDelimiterAlloc(self: &Self, allocator: &mem.Allocator, | ||
| 436 | delimiter: u8, max_size: usize) ![]u8 | ||
| 437 | { | ||
| 438 | var buf = Buffer.initNull(allocator); | ||
| 439 | defer buf.deinit(); | ||
| 440 | |||
| 441 | try self.readUntilDelimiterBuffer(self, &buf, delimiter, max_size); | ||
| 442 | return buf.toOwnedSlice(); | ||
| 443 | } | ||
| 483 | 444 | ||
| 484 | pub fn readIntBe(self: &InStream, comptime T: type) %T { | 445 | /// Returns the number of bytes read. If the number read is smaller than buf.len, it |
| 485 | return self.readInt(builtin.Endian.Big, T); | 446 | /// means the stream reached the end. Reaching the end of a stream is not an error |
| 486 | } | 447 | /// condition. |
| 448 | pub fn read(self: &Self, buffer: []u8) !usize { | ||
| 449 | return self.readFn(self, buffer); | ||
| 450 | } | ||
| 487 | 451 | ||
| 488 | pub fn readInt(self: &InStream, endian: builtin.Endian, comptime T: type) %T { | 452 | /// Same as `read` but end of stream returns `error.EndOfStream`. |
| 489 | var bytes: [@sizeOf(T)]u8 = undefined; | 453 | pub fn readNoEof(self: &Self, buf: []u8) !void { |
| 490 | try self.readNoEof(bytes[0..]); | 454 | const amt_read = try self.read(buf); |
| 491 | return mem.readInt(bytes, T, endian); | 455 | if (amt_read < buf.len) return error.EndOfStream; |
| 492 | } | 456 | } |
| 493 | 457 | ||
| 494 | pub fn readVarInt(self: &InStream, endian: builtin.Endian, comptime T: type, size: usize) %T { | 458 | /// Reads 1 byte from the stream or returns `error.EndOfStream`. |
| 495 | assert(size <= @sizeOf(T)); | 459 | pub fn readByte(self: &Self) !u8 { |
| 496 | assert(size <= 8); | 460 | var result: [1]u8 = undefined; |
| 497 | var input_buf: [8]u8 = undefined; | 461 | try self.readNoEof(result[0..]); |
| 498 | const input_slice = input_buf[0..size]; | 462 | return result[0]; |
| 499 | try self.readNoEof(input_slice); | 463 | } |
| 500 | return mem.readInt(input_slice, T, endian); | ||
| 501 | } | ||
| 502 | 464 | ||
| 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 | } | ||
| 503 | 469 | ||
| 504 | }; | 470 | pub fn readIntLe(self: &Self, comptime T: type) !T { |
| 471 | return self.readInt(builtin.Endian.Little, T); | ||
| 472 | } | ||
| 505 | 473 | ||
| 506 | pub const OutStream = struct { | 474 | pub fn readIntBe(self: &Self, comptime T: type) !T { |
| 507 | writeFn: fn(self: &OutStream, bytes: []const u8) %void, | 475 | return self.readInt(builtin.Endian.Big, T); |
| 476 | } | ||
| 508 | 477 | ||
| 509 | pub fn print(self: &OutStream, comptime format: []const u8, args: ...) %void { | 478 | pub fn readInt(self: &Self, endian: builtin.Endian, comptime T: type) !T { |
| 510 | return std.fmt.format(self, self.writeFn, format, args); | 479 | var bytes: [@sizeOf(T)]u8 = undefined; |
| 511 | } | 480 | try self.readNoEof(bytes[0..]); |
| 481 | return mem.readInt(bytes, T, endian); | ||
| 482 | } | ||
| 512 | 483 | ||
| 513 | pub fn write(self: &OutStream, bytes: []const u8) %void { | 484 | pub fn readVarInt(self: &Self, endian: builtin.Endian, comptime T: type, size: usize) !T { |
| 514 | return self.writeFn(self, bytes); | 485 | assert(size <= @sizeOf(T)); |
| 515 | } | 486 | assert(size <= 8); |
| 487 | var input_buf: [8]u8 = undefined; | ||
| 488 | const input_slice = input_buf[0..size]; | ||
| 489 | try self.readNoEof(input_slice); | ||
| 490 | return mem.readInt(input_slice, T, endian); | ||
| 491 | } | ||
| 492 | }; | ||
| 493 | } | ||
| 516 | 494 | ||
| 517 | pub fn writeByte(self: &OutStream, byte: u8) %void { | 495 | pub fn OutStream(comptime Error: type) type { |
| 518 | const slice = (&byte)[0..1]; | 496 | return struct { |
| 519 | return self.writeFn(self, slice); | 497 | const Self = this; |
| 520 | } | 498 | |
| 499 | writeFn: fn(self: &Self, bytes: []const u8) Error!void, | ||
| 521 | 500 | ||
| 522 | pub fn writeByteNTimes(self: &OutStream, byte: u8, n: usize) %void { | 501 | pub fn print(self: &Self, comptime format: []const u8, args: ...) !void { |
| 523 | const slice = (&byte)[0..1]; | 502 | return std.fmt.format(self, error, self.writeFn, format, args); |
| 524 | var i: usize = 0; | 503 | } |
| 525 | while (i < n) : (i += 1) { | 504 | |
| 526 | try self.writeFn(self, slice); | 505 | pub fn write(self: &Self, bytes: []const u8) !void { |
| 506 | return self.writeFn(self, bytes); | ||
| 507 | } | ||
| 508 | |||
| 509 | pub fn writeByte(self: &Self, byte: u8) !void { | ||
| 510 | const slice = (&byte)[0..1]; | ||
| 511 | return self.writeFn(self, slice); | ||
| 527 | } | 512 | } |
| 528 | } | 513 | |
| 529 | }; | 514 | pub fn writeByteNTimes(self: &Self, byte: u8, n: usize) !void { |
| 515 | const slice = (&byte)[0..1]; | ||
| 516 | var i: usize = 0; | ||
| 517 | while (i < n) : (i += 1) { | ||
| 518 | try self.writeFn(self, slice); | ||
| 519 | } | ||
| 520 | } | ||
| 521 | }; | ||
| 522 | } | ||
| 530 | 523 | ||
| 531 | /// `path` may need to be copied in memory to add a null terminating byte. In this case | 524 | /// `path` may need to be copied in memory to add a null terminating byte. In this case |
| 532 | /// a fixed size buffer of size `std.os.max_noalloc_path_len` is an attempted solution. If the fixed | 525 | /// a fixed size buffer of size `std.os.max_noalloc_path_len` is an attempted solution. If the fixed |
| 533 | /// size buffer is too small, and the provided allocator is null, `error.NameTooLong` is returned. | 526 | /// size buffer is too small, and the provided allocator is null, `error.NameTooLong` is returned. |
| 534 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. | 527 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. |
| 535 | pub fn writeFile(path: []const u8, data: []const u8, allocator: ?&mem.Allocator) %void { | 528 | pub fn writeFile(path: []const u8, data: []const u8, allocator: ?&mem.Allocator) !void { |
| 536 | var file = try File.openWrite(path, allocator); | 529 | var file = try File.openWrite(path, allocator); |
| 537 | defer file.close(); | 530 | defer file.close(); |
| 538 | try file.write(data); | 531 | try file.write(data); |
| 539 | } | 532 | } |
| 540 | 533 | ||
| 541 | /// On success, caller owns returned buffer. | 534 | /// On success, caller owns returned buffer. |
| 542 | pub fn readFileAlloc(path: []const u8, allocator: &mem.Allocator) %[]u8 { | 535 | pub fn readFileAlloc(path: []const u8, allocator: &mem.Allocator) ![]u8 { |
| 543 | return readFileAllocExtra(path, allocator, 0); | 536 | return readFileAllocExtra(path, allocator, 0); |
| 544 | } | 537 | } |
| 545 | /// On success, caller owns returned buffer. | 538 | /// On success, caller owns returned buffer. |
| 546 | /// Allocates extra_len extra bytes at the end of the file buffer, which are uninitialized. | 539 | /// Allocates extra_len extra bytes at the end of the file buffer, which are uninitialized. |
| 547 | pub fn readFileAllocExtra(path: []const u8, allocator: &mem.Allocator, extra_len: usize) %[]u8 { | 540 | pub fn readFileAllocExtra(path: []const u8, allocator: &mem.Allocator, extra_len: usize) ![]u8 { |
| 548 | var file = try File.openRead(path, allocator); | 541 | var file = try File.openRead(path, allocator); |
| 549 | defer file.close(); | 542 | defer file.close(); |
| 550 | 543 | ||
| ... | @@ -557,21 +550,24 @@ pub fn readFileAllocExtra(path: []const u8, allocator: &mem.Allocator, extra_len | ... | @@ -557,21 +550,24 @@ pub fn readFileAllocExtra(path: []const u8, allocator: &mem.Allocator, extra_len |
| 557 | return buf; | 550 | return buf; |
| 558 | } | 551 | } |
| 559 | 552 | ||
| 560 | pub const BufferedInStream = BufferedInStreamCustom(os.page_size); | 553 | pub fn BufferedInStream(comptime Error: type) type { |
| 554 | return BufferedInStreamCustom(os.page_size, Error); | ||
| 555 | } | ||
| 561 | 556 | ||
| 562 | pub fn BufferedInStreamCustom(comptime buffer_size: usize) type { | 557 | pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) type { |
| 563 | return struct { | 558 | return struct { |
| 564 | const Self = this; | 559 | const Self = this; |
| 560 | const Stream = InStream(Error); | ||
| 565 | 561 | ||
| 566 | pub stream: InStream, | 562 | pub stream: Stream, |
| 567 | 563 | ||
| 568 | unbuffered_in_stream: &InStream, | 564 | unbuffered_in_stream: &Stream, |
| 569 | 565 | ||
| 570 | buffer: [buffer_size]u8, | 566 | buffer: [buffer_size]u8, |
| 571 | start_index: usize, | 567 | start_index: usize, |
| 572 | end_index: usize, | 568 | end_index: usize, |
| 573 | 569 | ||
| 574 | pub fn init(unbuffered_in_stream: &InStream) Self { | 570 | pub fn init(unbuffered_in_stream: &Stream) Self { |
| 575 | return Self { | 571 | return Self { |
| 576 | .unbuffered_in_stream = unbuffered_in_stream, | 572 | .unbuffered_in_stream = unbuffered_in_stream, |
| 577 | .buffer = undefined, | 573 | .buffer = undefined, |
| ... | @@ -583,13 +579,13 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize) type { | ... | @@ -583,13 +579,13 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize) type { |
| 583 | .start_index = buffer_size, | 579 | .start_index = buffer_size, |
| 584 | .end_index = buffer_size, | 580 | .end_index = buffer_size, |
| 585 | 581 | ||
| 586 | .stream = InStream { | 582 | .stream = Stream { |
| 587 | .readFn = readFn, | 583 | .readFn = readFn, |
| 588 | }, | 584 | }, |
| 589 | }; | 585 | }; |
| 590 | } | 586 | } |
| 591 | 587 | ||
| 592 | fn readFn(in_stream: &InStream, dest: []u8) %usize { | 588 | fn readFn(in_stream: &Stream, dest: []u8) !usize { |
| 593 | const self = @fieldParentPtr(Self, "stream", in_stream); | 589 | const self = @fieldParentPtr(Self, "stream", in_stream); |
| 594 | 590 | ||
| 595 | var dest_index: usize = 0; | 591 | var dest_index: usize = 0; |
| ... | @@ -628,31 +624,34 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize) type { | ... | @@ -628,31 +624,34 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize) type { |
| 628 | }; | 624 | }; |
| 629 | } | 625 | } |
| 630 | 626 | ||
| 631 | pub const BufferedOutStream = BufferedOutStreamCustom(os.page_size); | 627 | pub fn BufferedOutStream(comptime Error: type) type { |
| 628 | return BufferedOutStreamCustom(os.page_size, Error); | ||
| 629 | } | ||
| 632 | 630 | ||
| 633 | pub fn BufferedOutStreamCustom(comptime buffer_size: usize) type { | 631 | pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime Error: type) type { |
| 634 | return struct { | 632 | return struct { |
| 635 | const Self = this; | 633 | const Self = this; |
| 634 | const Stream = OutStream(Error); | ||
| 636 | 635 | ||
| 637 | pub stream: OutStream, | 636 | pub stream: Stream, |
| 638 | 637 | ||
| 639 | unbuffered_out_stream: &OutStream, | 638 | unbuffered_out_stream: &Stream, |
| 640 | 639 | ||
| 641 | buffer: [buffer_size]u8, | 640 | buffer: [buffer_size]u8, |
| 642 | index: usize, | 641 | index: usize, |
| 643 | 642 | ||
| 644 | pub fn init(unbuffered_out_stream: &OutStream) Self { | 643 | pub fn init(unbuffered_out_stream: &Stream) Self { |
| 645 | return Self { | 644 | return Self { |
| 646 | .unbuffered_out_stream = unbuffered_out_stream, | 645 | .unbuffered_out_stream = unbuffered_out_stream, |
| 647 | .buffer = undefined, | 646 | .buffer = undefined, |
| 648 | .index = 0, | 647 | .index = 0, |
| 649 | .stream = OutStream { | 648 | .stream = Stream { |
| 650 | .writeFn = writeFn, | 649 | .writeFn = writeFn, |
| 651 | }, | 650 | }, |
| 652 | }; | 651 | }; |
| 653 | } | 652 | } |
| 654 | 653 | ||
| 655 | pub fn flush(self: &Self) %void { | 654 | pub fn flush(self: &Self) !void { |
| 656 | if (self.index == 0) | 655 | if (self.index == 0) |
| 657 | return; | 656 | return; |
| 658 | 657 | ||
| ... | @@ -660,7 +659,7 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize) type { | ... | @@ -660,7 +659,7 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize) type { |
| 660 | self.index = 0; | 659 | self.index = 0; |
| 661 | } | 660 | } |
| 662 | 661 | ||
| 663 | fn writeFn(out_stream: &OutStream, bytes: []const u8) %void { | 662 | fn writeFn(out_stream: &Stream, bytes: []const u8) !void { |
| 664 | const self = @fieldParentPtr(Self, "stream", out_stream); | 663 | const self = @fieldParentPtr(Self, "stream", out_stream); |
| 665 | 664 | ||
| 666 | if (bytes.len >= self.buffer.len) { | 665 | if (bytes.len >= self.buffer.len) { |
| ... | @@ -687,18 +686,21 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize) type { | ... | @@ -687,18 +686,21 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize) type { |
| 687 | /// Implementation of OutStream trait for Buffer | 686 | /// Implementation of OutStream trait for Buffer |
| 688 | pub const BufferOutStream = struct { | 687 | pub const BufferOutStream = struct { |
| 689 | buffer: &Buffer, | 688 | buffer: &Buffer, |
| 690 | stream: OutStream, | 689 | stream: Stream, |
| 690 | |||
| 691 | pub const Error = error{OutOfMemory}; | ||
| 692 | pub const Stream = OutStream(Error); | ||
| 691 | 693 | ||
| 692 | pub fn init(buffer: &Buffer) BufferOutStream { | 694 | pub fn init(buffer: &Buffer) BufferOutStream { |
| 693 | return BufferOutStream { | 695 | return BufferOutStream { |
| 694 | .buffer = buffer, | 696 | .buffer = buffer, |
| 695 | .stream = OutStream { | 697 | .stream = Stream { |
| 696 | .writeFn = writeFn, | 698 | .writeFn = writeFn, |
| 697 | }, | 699 | }, |
| 698 | }; | 700 | }; |
| 699 | } | 701 | } |
| 700 | 702 | ||
| 701 | fn writeFn(out_stream: &OutStream, bytes: []const u8) %void { | 703 | fn writeFn(out_stream: &Stream, bytes: []const u8) !void { |
| 702 | const self = @fieldParentPtr(BufferOutStream, "stream", out_stream); | 704 | const self = @fieldParentPtr(BufferOutStream, "stream", out_stream); |
| 703 | return self.buffer.append(bytes); | 705 | return self.buffer.append(bytes); |
| 704 | } | 706 | } |
std/io_test.zig+2-2| ... | @@ -17,7 +17,7 @@ test "write a file, read it, then delete it" { | ... | @@ -17,7 +17,7 @@ test "write a file, read it, then delete it" { |
| 17 | defer file.close(); | 17 | defer file.close(); |
| 18 | 18 | ||
| 19 | var file_out_stream = io.FileOutStream.init(&file); | 19 | var file_out_stream = io.FileOutStream.init(&file); |
| 20 | var buf_stream = io.BufferedOutStream.init(&file_out_stream.stream); | 20 | var buf_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream); |
| 21 | const st = &buf_stream.stream; | 21 | const st = &buf_stream.stream; |
| 22 | try st.print("begin"); | 22 | try st.print("begin"); |
| 23 | try st.write(data[0..]); | 23 | try st.write(data[0..]); |
| ... | @@ -33,7 +33,7 @@ test "write a file, read it, then delete it" { | ... | @@ -33,7 +33,7 @@ test "write a file, read it, then delete it" { |
| 33 | assert(file_size == expected_file_size); | 33 | assert(file_size == expected_file_size); |
| 34 | 34 | ||
| 35 | var file_in_stream = io.FileInStream.init(&file); | 35 | var file_in_stream = io.FileInStream.init(&file); |
| 36 | var buf_stream = io.BufferedInStream.init(&file_in_stream.stream); | 36 | var buf_stream = io.BufferedInStream(io.FileInStream.Error).init(&file_in_stream.stream); |
| 37 | const st = &buf_stream.stream; | 37 | const st = &buf_stream.stream; |
| 38 | const contents = try st.readAllAlloc(allocator, 2 * 1024); | 38 | const contents = try st.readAllAlloc(allocator, 2 * 1024); |
| 39 | defer allocator.free(contents); | 39 | defer allocator.free(contents); |
std/linked_list.zig+2-2| ... | @@ -190,7 +190,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na | ... | @@ -190,7 +190,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na |
| 190 | /// | 190 | /// |
| 191 | /// Returns: | 191 | /// Returns: |
| 192 | /// A pointer to the new node. | 192 | /// A pointer to the new node. |
| 193 | pub fn allocateNode(list: &Self, allocator: &Allocator) %&Node { | 193 | pub fn allocateNode(list: &Self, allocator: &Allocator) !&Node { |
| 194 | comptime assert(!isIntrusive()); | 194 | comptime assert(!isIntrusive()); |
| 195 | return allocator.create(Node); | 195 | return allocator.create(Node); |
| 196 | } | 196 | } |
| ... | @@ -213,7 +213,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na | ... | @@ -213,7 +213,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na |
| 213 | /// | 213 | /// |
| 214 | /// Returns: | 214 | /// Returns: |
| 215 | /// A pointer to the new node. | 215 | /// A pointer to the new node. |
| 216 | pub fn createNode(list: &Self, data: &const T, allocator: &Allocator) %&Node { | 216 | pub fn createNode(list: &Self, data: &const T, allocator: &Allocator) !&Node { |
| 217 | comptime assert(!isIntrusive()); | 217 | comptime assert(!isIntrusive()); |
| 218 | var node = try list.allocateNode(allocator); | 218 | var node = try list.allocateNode(allocator); |
| 219 | *node = Node.init(data); | 219 | *node = Node.init(data); |
std/math/index.zig+13-31| ... | @@ -191,30 +191,26 @@ test "math.max" { | ... | @@ -191,30 +191,26 @@ test "math.max" { |
| 191 | assert(max(i32(-1), i32(2)) == 2); | 191 | assert(max(i32(-1), i32(2)) == 2); |
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | error Overflow; | 194 | pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) { |
| 195 | pub fn mul(comptime T: type, a: T, b: T) %T { | ||
| 196 | var answer: T = undefined; | 195 | var answer: T = undefined; |
| 197 | return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer; | 196 | return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer; |
| 198 | } | 197 | } |
| 199 | 198 | ||
| 200 | error Overflow; | 199 | pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) { |
| 201 | pub fn add(comptime T: type, a: T, b: T) %T { | ||
| 202 | var answer: T = undefined; | 200 | var answer: T = undefined; |
| 203 | return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer; | 201 | return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer; |
| 204 | } | 202 | } |
| 205 | 203 | ||
| 206 | error Overflow; | 204 | pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) { |
| 207 | pub fn sub(comptime T: type, a: T, b: T) %T { | ||
| 208 | var answer: T = undefined; | 205 | var answer: T = undefined; |
| 209 | return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer; | 206 | return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer; |
| 210 | } | 207 | } |
| 211 | 208 | ||
| 212 | pub fn negate(x: var) %@typeOf(x) { | 209 | pub fn negate(x: var) !@typeOf(x) { |
| 213 | return sub(@typeOf(x), 0, x); | 210 | return sub(@typeOf(x), 0, x); |
| 214 | } | 211 | } |
| 215 | 212 | ||
| 216 | error Overflow; | 213 | pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T { |
| 217 | pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) %T { | ||
| 218 | var answer: T = undefined; | 214 | var answer: T = undefined; |
| 219 | return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer; | 215 | return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer; |
| 220 | } | 216 | } |
| ... | @@ -323,8 +319,7 @@ fn testOverflow() void { | ... | @@ -323,8 +319,7 @@ fn testOverflow() void { |
| 323 | } | 319 | } |
| 324 | 320 | ||
| 325 | 321 | ||
| 326 | error Overflow; | 322 | pub fn absInt(x: var) !@typeOf(x) { |
| 327 | pub fn absInt(x: var) %@typeOf(x) { | ||
| 328 | const T = @typeOf(x); | 323 | const T = @typeOf(x); |
| 329 | comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt | 324 | comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt |
| 330 | comptime assert(T.is_signed); // must pass a signed integer to absInt | 325 | comptime assert(T.is_signed); // must pass a signed integer to absInt |
| ... | @@ -347,9 +342,7 @@ fn testAbsInt() void { | ... | @@ -347,9 +342,7 @@ fn testAbsInt() void { |
| 347 | 342 | ||
| 348 | pub const absFloat = @import("fabs.zig").fabs; | 343 | pub const absFloat = @import("fabs.zig").fabs; |
| 349 | 344 | ||
| 350 | error DivisionByZero; | 345 | pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T { |
| 351 | error Overflow; | ||
| 352 | pub fn divTrunc(comptime T: type, numerator: T, denominator: T) %T { | ||
| 353 | @setRuntimeSafety(false); | 346 | @setRuntimeSafety(false); |
| 354 | if (denominator == 0) | 347 | if (denominator == 0) |
| 355 | return error.DivisionByZero; | 348 | return error.DivisionByZero; |
| ... | @@ -372,9 +365,7 @@ fn testDivTrunc() void { | ... | @@ -372,9 +365,7 @@ fn testDivTrunc() void { |
| 372 | assert((divTrunc(f32, -5.0, 3.0) catch unreachable) == -1.0); | 365 | assert((divTrunc(f32, -5.0, 3.0) catch unreachable) == -1.0); |
| 373 | } | 366 | } |
| 374 | 367 | ||
| 375 | error DivisionByZero; | 368 | pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T { |
| 376 | error Overflow; | ||
| 377 | pub fn divFloor(comptime T: type, numerator: T, denominator: T) %T { | ||
| 378 | @setRuntimeSafety(false); | 369 | @setRuntimeSafety(false); |
| 379 | if (denominator == 0) | 370 | if (denominator == 0) |
| 380 | return error.DivisionByZero; | 371 | return error.DivisionByZero; |
| ... | @@ -397,10 +388,7 @@ fn testDivFloor() void { | ... | @@ -397,10 +388,7 @@ fn testDivFloor() void { |
| 397 | assert((divFloor(f32, -5.0, 3.0) catch unreachable) == -2.0); | 388 | assert((divFloor(f32, -5.0, 3.0) catch unreachable) == -2.0); |
| 398 | } | 389 | } |
| 399 | 390 | ||
| 400 | error DivisionByZero; | 391 | pub fn divExact(comptime T: type, numerator: T, denominator: T) !T { |
| 401 | error Overflow; | ||
| 402 | error UnexpectedRemainder; | ||
| 403 | pub fn divExact(comptime T: type, numerator: T, denominator: T) %T { | ||
| 404 | @setRuntimeSafety(false); | 392 | @setRuntimeSafety(false); |
| 405 | if (denominator == 0) | 393 | if (denominator == 0) |
| 406 | return error.DivisionByZero; | 394 | return error.DivisionByZero; |
| ... | @@ -428,9 +416,7 @@ fn testDivExact() void { | ... | @@ -428,9 +416,7 @@ fn testDivExact() void { |
| 428 | if (divExact(f32, 5.0, 2.0)) |_| unreachable else |err| assert(err == error.UnexpectedRemainder); | 416 | if (divExact(f32, 5.0, 2.0)) |_| unreachable else |err| assert(err == error.UnexpectedRemainder); |
| 429 | } | 417 | } |
| 430 | 418 | ||
| 431 | error DivisionByZero; | 419 | pub fn mod(comptime T: type, numerator: T, denominator: T) !T { |
| 432 | error NegativeDenominator; | ||
| 433 | pub fn mod(comptime T: type, numerator: T, denominator: T) %T { | ||
| 434 | @setRuntimeSafety(false); | 420 | @setRuntimeSafety(false); |
| 435 | if (denominator == 0) | 421 | if (denominator == 0) |
| 436 | return error.DivisionByZero; | 422 | return error.DivisionByZero; |
| ... | @@ -455,9 +441,7 @@ fn testMod() void { | ... | @@ -455,9 +441,7 @@ fn testMod() void { |
| 455 | if (mod(f32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); | 441 | if (mod(f32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); |
| 456 | } | 442 | } |
| 457 | 443 | ||
| 458 | error DivisionByZero; | 444 | pub fn rem(comptime T: type, numerator: T, denominator: T) !T { |
| 459 | error NegativeDenominator; | ||
| 460 | pub fn rem(comptime T: type, numerator: T, denominator: T) %T { | ||
| 461 | @setRuntimeSafety(false); | 445 | @setRuntimeSafety(false); |
| 462 | if (denominator == 0) | 446 | if (denominator == 0) |
| 463 | return error.DivisionByZero; | 447 | return error.DivisionByZero; |
| ... | @@ -505,8 +489,7 @@ test "math.absCast" { | ... | @@ -505,8 +489,7 @@ test "math.absCast" { |
| 505 | 489 | ||
| 506 | /// Returns the negation of the integer parameter. | 490 | /// Returns the negation of the integer parameter. |
| 507 | /// Result is a signed integer. | 491 | /// Result is a signed integer. |
| 508 | error Overflow; | 492 | pub fn negateCast(x: var) !@IntType(true, @typeOf(x).bit_count) { |
| 509 | pub fn negateCast(x: var) %@IntType(true, @typeOf(x).bit_count) { | ||
| 510 | if (@typeOf(x).is_signed) | 493 | if (@typeOf(x).is_signed) |
| 511 | return negate(x); | 494 | return negate(x); |
| 512 | 495 | ||
| ... | @@ -532,8 +515,7 @@ test "math.negateCast" { | ... | @@ -532,8 +515,7 @@ test "math.negateCast" { |
| 532 | 515 | ||
| 533 | /// Cast an integer to a different integer type. If the value doesn't fit, | 516 | /// Cast an integer to a different integer type. If the value doesn't fit, |
| 534 | /// return an error. | 517 | /// return an error. |
| 535 | error Overflow; | 518 | pub fn cast(comptime T: type, x: var) !T { |
| 536 | pub fn cast(comptime T: type, x: var) %T { | ||
| 537 | comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer | 519 | comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer |
| 538 | if (x > @maxValue(T)) { | 520 | if (x > @maxValue(T)) { |
| 539 | return error.Overflow; | 521 | return error.Overflow; |
std/mem.zig+15-15| ... | @@ -4,13 +4,13 @@ const assert = debug.assert; | ... | @@ -4,13 +4,13 @@ const assert = debug.assert; |
| 4 | const math = std.math; | 4 | const math = std.math; |
| 5 | const builtin = @import("builtin"); | 5 | const builtin = @import("builtin"); |
| 6 | 6 | ||
| 7 | error OutOfMemory; | ||
| 8 | |||
| 9 | pub const Allocator = struct { | 7 | pub const Allocator = struct { |
| 8 | const Error = error {OutOfMemory}; | ||
| 9 | |||
| 10 | /// Allocate byte_count bytes and return them in a slice, with the | 10 | /// Allocate byte_count bytes and return them in a slice, with the |
| 11 | /// slice's pointer aligned at least to alignment bytes. | 11 | /// slice's pointer aligned at least to alignment bytes. |
| 12 | /// The returned newly allocated memory is undefined. | 12 | /// The returned newly allocated memory is undefined. |
| 13 | allocFn: fn (self: &Allocator, byte_count: usize, alignment: u29) %[]u8, | 13 | allocFn: fn (self: &Allocator, byte_count: usize, alignment: u29) Error![]u8, |
| 14 | 14 | ||
| 15 | /// If `new_byte_count > old_mem.len`: | 15 | /// If `new_byte_count > old_mem.len`: |
| 16 | /// * `old_mem.len` is the same as what was returned from allocFn or reallocFn. | 16 | /// * `old_mem.len` is the same as what was returned from allocFn or reallocFn. |
| ... | @@ -21,12 +21,12 @@ pub const Allocator = struct { | ... | @@ -21,12 +21,12 @@ pub const Allocator = struct { |
| 21 | /// * alignment <= alignment of old_mem.ptr | 21 | /// * alignment <= alignment of old_mem.ptr |
| 22 | /// | 22 | /// |
| 23 | /// The returned newly allocated memory is undefined. | 23 | /// The returned newly allocated memory is undefined. |
| 24 | reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) %[]u8, | 24 | reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) Error![]u8, |
| 25 | 25 | ||
| 26 | /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn` | 26 | /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn` |
| 27 | freeFn: fn (self: &Allocator, old_mem: []u8) void, | 27 | freeFn: fn (self: &Allocator, old_mem: []u8) void, |
| 28 | 28 | ||
| 29 | fn create(self: &Allocator, comptime T: type) %&T { | 29 | fn create(self: &Allocator, comptime T: type) !&T { |
| 30 | const slice = try self.alloc(T, 1); | 30 | const slice = try self.alloc(T, 1); |
| 31 | return &slice[0]; | 31 | return &slice[0]; |
| 32 | } | 32 | } |
| ... | @@ -35,14 +35,14 @@ pub const Allocator = struct { | ... | @@ -35,14 +35,14 @@ pub const Allocator = struct { |
| 35 | self.free(ptr[0..1]); | 35 | self.free(ptr[0..1]); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | fn alloc(self: &Allocator, comptime T: type, n: usize) %[]T { | 38 | fn alloc(self: &Allocator, comptime T: type, n: usize) ![]T { |
| 39 | return self.alignedAlloc(T, @alignOf(T), n); | 39 | return self.alignedAlloc(T, @alignOf(T), n); |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29, | 42 | fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29, |
| 43 | n: usize) %[]align(alignment) T | 43 | n: usize) ![]align(alignment) T |
| 44 | { | 44 | { |
| 45 | const byte_count = try math.mul(usize, @sizeOf(T), n); | 45 | const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory; |
| 46 | const byte_slice = try self.allocFn(self, byte_count, alignment); | 46 | const byte_slice = try self.allocFn(self, byte_count, alignment); |
| 47 | // This loop should get optimized out in ReleaseFast mode | 47 | // This loop should get optimized out in ReleaseFast mode |
| 48 | for (byte_slice) |*byte| { | 48 | for (byte_slice) |*byte| { |
| ... | @@ -51,19 +51,19 @@ pub const Allocator = struct { | ... | @@ -51,19 +51,19 @@ pub const Allocator = struct { |
| 51 | return ([]align(alignment) T)(@alignCast(alignment, byte_slice)); | 51 | return ([]align(alignment) T)(@alignCast(alignment, byte_slice)); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | fn realloc(self: &Allocator, comptime T: type, old_mem: []T, n: usize) %[]T { | 54 | fn realloc(self: &Allocator, comptime T: type, old_mem: []T, n: usize) ![]T { |
| 55 | return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n); | 55 | return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | fn alignedRealloc(self: &Allocator, comptime T: type, comptime alignment: u29, | 58 | fn alignedRealloc(self: &Allocator, comptime T: type, comptime alignment: u29, |
| 59 | old_mem: []align(alignment) T, n: usize) %[]align(alignment) T | 59 | old_mem: []align(alignment) T, n: usize) ![]align(alignment) T |
| 60 | { | 60 | { |
| 61 | if (old_mem.len == 0) { | 61 | if (old_mem.len == 0) { |
| 62 | return self.alloc(T, n); | 62 | return self.alloc(T, n); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | const old_byte_slice = ([]u8)(old_mem); | 65 | const old_byte_slice = ([]u8)(old_mem); |
| 66 | const byte_count = try math.mul(usize, @sizeOf(T), n); | 66 | const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory; |
| 67 | const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment); | 67 | const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment); |
| 68 | // This loop should get optimized out in ReleaseFast mode | 68 | // This loop should get optimized out in ReleaseFast mode |
| 69 | for (byte_slice[old_byte_slice.len..]) |*byte| { | 69 | for (byte_slice[old_byte_slice.len..]) |*byte| { |
| ... | @@ -123,7 +123,7 @@ pub const FixedBufferAllocator = struct { | ... | @@ -123,7 +123,7 @@ pub const FixedBufferAllocator = struct { |
| 123 | }; | 123 | }; |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | fn alloc(allocator: &Allocator, n: usize, alignment: u29) %[]u8 { | 126 | fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 { |
| 127 | const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator); | 127 | const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator); |
| 128 | const addr = @ptrToInt(&self.buffer[self.end_index]); | 128 | const addr = @ptrToInt(&self.buffer[self.end_index]); |
| 129 | const rem = @rem(addr, alignment); | 129 | const rem = @rem(addr, alignment); |
| ... | @@ -138,7 +138,7 @@ pub const FixedBufferAllocator = struct { | ... | @@ -138,7 +138,7 @@ pub const FixedBufferAllocator = struct { |
| 138 | return result; | 138 | return result; |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) %[]u8 { | 141 | fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 { |
| 142 | if (new_size <= old_mem.len) { | 142 | if (new_size <= old_mem.len) { |
| 143 | return old_mem[0..new_size]; | 143 | return old_mem[0..new_size]; |
| 144 | } else { | 144 | } else { |
| ... | @@ -197,7 +197,7 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool { | ... | @@ -197,7 +197,7 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool { |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | /// Copies ::m to newly allocated memory. Caller is responsible to free it. | 199 | /// Copies ::m to newly allocated memory. Caller is responsible to free it. |
| 200 | pub fn dupe(allocator: &Allocator, comptime T: type, m: []const T) %[]T { | 200 | pub fn dupe(allocator: &Allocator, comptime T: type, m: []const T) ![]T { |
| 201 | const new_buf = try allocator.alloc(T, m.len); | 201 | const new_buf = try allocator.alloc(T, m.len); |
| 202 | copy(T, new_buf, m); | 202 | copy(T, new_buf, m); |
| 203 | return new_buf; | 203 | return new_buf; |
| ... | @@ -428,7 +428,7 @@ const SplitIterator = struct { | ... | @@ -428,7 +428,7 @@ const SplitIterator = struct { |
| 428 | 428 | ||
| 429 | /// Naively combines a series of strings with a separator. | 429 | /// Naively combines a series of strings with a separator. |
| 430 | /// Allocates memory for the result, which must be freed by the caller. | 430 | /// Allocates memory for the result, which must be freed by the caller. |
| 431 | pub fn join(allocator: &Allocator, sep: u8, strings: ...) %[]u8 { | 431 | pub fn join(allocator: &Allocator, sep: u8, strings: ...) ![]u8 { |
| 432 | comptime assert(strings.len >= 1); | 432 | comptime assert(strings.len >= 1); |
| 433 | var total_strings_len: usize = strings.len; // 1 sep per string | 433 | var total_strings_len: usize = strings.len; // 1 sep per string |
| 434 | { | 434 | { |
std/net.zig+9-25| ... | @@ -5,19 +5,10 @@ const endian = std.endian; | ... | @@ -5,19 +5,10 @@ const endian = std.endian; |
| 5 | 5 | ||
| 6 | // TODO don't trust this file, it bit rotted. start over | 6 | // TODO don't trust this file, it bit rotted. start over |
| 7 | 7 | ||
| 8 | error SigInterrupt; | ||
| 9 | error Io; | ||
| 10 | error TimedOut; | ||
| 11 | error ConnectionReset; | ||
| 12 | error ConnectionRefused; | ||
| 13 | error OutOfMemory; | ||
| 14 | error NotSocket; | ||
| 15 | error BadFd; | ||
| 16 | |||
| 17 | const Connection = struct { | 8 | const Connection = struct { |
| 18 | socket_fd: i32, | 9 | socket_fd: i32, |
| 19 | 10 | ||
| 20 | pub fn send(c: Connection, buf: []const u8) %usize { | 11 | pub fn send(c: Connection, buf: []const u8) !usize { |
| 21 | const send_ret = linux.sendto(c.socket_fd, buf.ptr, buf.len, 0, null, 0); | 12 | const send_ret = linux.sendto(c.socket_fd, buf.ptr, buf.len, 0, null, 0); |
| 22 | const send_err = linux.getErrno(send_ret); | 13 | const send_err = linux.getErrno(send_ret); |
| 23 | switch (send_err) { | 14 | switch (send_err) { |
| ... | @@ -31,7 +22,7 @@ const Connection = struct { | ... | @@ -31,7 +22,7 @@ const Connection = struct { |
| 31 | } | 22 | } |
| 32 | } | 23 | } |
| 33 | 24 | ||
| 34 | pub fn recv(c: Connection, buf: []u8) %[]u8 { | 25 | pub fn recv(c: Connection, buf: []u8) ![]u8 { |
| 35 | const recv_ret = linux.recvfrom(c.socket_fd, buf.ptr, buf.len, 0, null, null); | 26 | const recv_ret = linux.recvfrom(c.socket_fd, buf.ptr, buf.len, 0, null, null); |
| 36 | const recv_err = linux.getErrno(recv_ret); | 27 | const recv_err = linux.getErrno(recv_ret); |
| 37 | switch (recv_err) { | 28 | switch (recv_err) { |
| ... | @@ -48,7 +39,7 @@ const Connection = struct { | ... | @@ -48,7 +39,7 @@ const Connection = struct { |
| 48 | } | 39 | } |
| 49 | } | 40 | } |
| 50 | 41 | ||
| 51 | pub fn close(c: Connection) %void { | 42 | pub fn close(c: Connection) !void { |
| 52 | switch (linux.getErrno(linux.close(c.socket_fd))) { | 43 | switch (linux.getErrno(linux.close(c.socket_fd))) { |
| 53 | 0 => return, | 44 | 0 => return, |
| 54 | linux.EBADF => unreachable, | 45 | linux.EBADF => unreachable, |
| ... | @@ -66,7 +57,7 @@ const Address = struct { | ... | @@ -66,7 +57,7 @@ const Address = struct { |
| 66 | sort_key: i32, | 57 | sort_key: i32, |
| 67 | }; | 58 | }; |
| 68 | 59 | ||
| 69 | pub fn lookup(hostname: []const u8, out_addrs: []Address) %[]Address { | 60 | pub fn lookup(hostname: []const u8, out_addrs: []Address) ![]Address { |
| 70 | if (hostname.len == 0) { | 61 | if (hostname.len == 0) { |
| 71 | 62 | ||
| 72 | unreachable; // TODO | 63 | unreachable; // TODO |
| ... | @@ -75,7 +66,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) %[]Address { | ... | @@ -75,7 +66,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) %[]Address { |
| 75 | unreachable; // TODO | 66 | unreachable; // TODO |
| 76 | } | 67 | } |
| 77 | 68 | ||
| 78 | pub fn connectAddr(addr: &Address, port: u16) %Connection { | 69 | pub fn connectAddr(addr: &Address, port: u16) !Connection { |
| 79 | const socket_ret = linux.socket(addr.family, linux.SOCK_STREAM, linux.PROTO_tcp); | 70 | const socket_ret = linux.socket(addr.family, linux.SOCK_STREAM, linux.PROTO_tcp); |
| 80 | const socket_err = linux.getErrno(socket_ret); | 71 | const socket_err = linux.getErrno(socket_ret); |
| 81 | if (socket_err > 0) { | 72 | if (socket_err > 0) { |
| ... | @@ -118,7 +109,7 @@ pub fn connectAddr(addr: &Address, port: u16) %Connection { | ... | @@ -118,7 +109,7 @@ pub fn connectAddr(addr: &Address, port: u16) %Connection { |
| 118 | }; | 109 | }; |
| 119 | } | 110 | } |
| 120 | 111 | ||
| 121 | pub fn connect(hostname: []const u8, port: u16) %Connection { | 112 | pub fn connect(hostname: []const u8, port: u16) !Connection { |
| 122 | var addrs_buf: [1]Address = undefined; | 113 | var addrs_buf: [1]Address = undefined; |
| 123 | const addrs_slice = try lookup(hostname, addrs_buf[0..]); | 114 | const addrs_slice = try lookup(hostname, addrs_buf[0..]); |
| 124 | const main_addr = &addrs_slice[0]; | 115 | const main_addr = &addrs_slice[0]; |
| ... | @@ -126,9 +117,7 @@ pub fn connect(hostname: []const u8, port: u16) %Connection { | ... | @@ -126,9 +117,7 @@ pub fn connect(hostname: []const u8, port: u16) %Connection { |
| 126 | return connectAddr(main_addr, port); | 117 | return connectAddr(main_addr, port); |
| 127 | } | 118 | } |
| 128 | 119 | ||
| 129 | error InvalidIpLiteral; | 120 | pub fn parseIpLiteral(buf: []const u8) !Address { |
| 130 | |||
| 131 | pub fn parseIpLiteral(buf: []const u8) %Address { | ||
| 132 | 121 | ||
| 133 | return error.InvalidIpLiteral; | 122 | return error.InvalidIpLiteral; |
| 134 | } | 123 | } |
| ... | @@ -146,12 +135,7 @@ fn hexDigit(c: u8) u8 { | ... | @@ -146,12 +135,7 @@ fn hexDigit(c: u8) u8 { |
| 146 | } | 135 | } |
| 147 | } | 136 | } |
| 148 | 137 | ||
| 149 | error InvalidChar; | 138 | fn parseIp6(buf: []const u8) !Address { |
| 150 | error Overflow; | ||
| 151 | error JunkAtEnd; | ||
| 152 | error Incomplete; | ||
| 153 | |||
| 154 | fn parseIp6(buf: []const u8) %Address { | ||
| 155 | var result: Address = undefined; | 139 | var result: Address = undefined; |
| 156 | result.family = linux.AF_INET6; | 140 | result.family = linux.AF_INET6; |
| 157 | result.scope_id = 0; | 141 | result.scope_id = 0; |
| ... | @@ -232,7 +216,7 @@ fn parseIp6(buf: []const u8) %Address { | ... | @@ -232,7 +216,7 @@ fn parseIp6(buf: []const u8) %Address { |
| 232 | return error.Incomplete; | 216 | return error.Incomplete; |
| 233 | } | 217 | } |
| 234 | 218 | ||
| 235 | fn parseIp4(buf: []const u8) %u32 { | 219 | fn parseIp4(buf: []const u8) !u32 { |
| 236 | var result: u32 = undefined; | 220 | var result: u32 = undefined; |
| 237 | const out_ptr = ([]u8)((&result)[0..1]); | 221 | const out_ptr = ([]u8)((&result)[0..1]); |
| 238 | 222 |
std/os/child_process.zig+49-34| ... | @@ -13,10 +13,6 @@ const builtin = @import("builtin"); | ... | @@ -13,10 +13,6 @@ const builtin = @import("builtin"); |
| 13 | const Os = builtin.Os; | 13 | const Os = builtin.Os; |
| 14 | const LinkedList = std.LinkedList; | 14 | const LinkedList = std.LinkedList; |
| 15 | 15 | ||
| 16 | error PermissionDenied; | ||
| 17 | error ProcessNotFound; | ||
| 18 | error InvalidName; | ||
| 19 | |||
| 20 | var children_nodes = LinkedList(&ChildProcess).init(); | 16 | var children_nodes = LinkedList(&ChildProcess).init(); |
| 21 | 17 | ||
| 22 | const is_windows = builtin.os == Os.windows; | 18 | const is_windows = builtin.os == Os.windows; |
| ... | @@ -32,7 +28,7 @@ pub const ChildProcess = struct { | ... | @@ -32,7 +28,7 @@ pub const ChildProcess = struct { |
| 32 | pub stdout: ?io.File, | 28 | pub stdout: ?io.File, |
| 33 | pub stderr: ?io.File, | 29 | pub stderr: ?io.File, |
| 34 | 30 | ||
| 35 | pub term: ?%Term, | 31 | pub term: ?(SpawnError!Term), |
| 36 | 32 | ||
| 37 | pub argv: []const []const u8, | 33 | pub argv: []const []const u8, |
| 38 | 34 | ||
| ... | @@ -58,6 +54,25 @@ pub const ChildProcess = struct { | ... | @@ -58,6 +54,25 @@ pub const ChildProcess = struct { |
| 58 | err_pipe: if (is_windows) void else [2]i32, | 54 | err_pipe: if (is_windows) void else [2]i32, |
| 59 | llnode: if (is_windows) void else LinkedList(&ChildProcess).Node, | 55 | llnode: if (is_windows) void else LinkedList(&ChildProcess).Node, |
| 60 | 56 | ||
| 57 | pub const SpawnError = error { | ||
| 58 | ProcessFdQuotaExceeded, | ||
| 59 | Unexpected, | ||
| 60 | NotDir, | ||
| 61 | SystemResources, | ||
| 62 | FileNotFound, | ||
| 63 | NameTooLong, | ||
| 64 | SymLinkLoop, | ||
| 65 | FileSystem, | ||
| 66 | OutOfMemory, | ||
| 67 | AccessDenied, | ||
| 68 | PermissionDenied, | ||
| 69 | InvalidUserId, | ||
| 70 | ResourceLimitReached, | ||
| 71 | InvalidExe, | ||
| 72 | IsDir, | ||
| 73 | FileBusy, | ||
| 74 | }; | ||
| 75 | |||
| 61 | pub const Term = union(enum) { | 76 | pub const Term = union(enum) { |
| 62 | Exited: i32, | 77 | Exited: i32, |
| 63 | Signal: i32, | 78 | Signal: i32, |
| ... | @@ -74,7 +89,7 @@ pub const ChildProcess = struct { | ... | @@ -74,7 +89,7 @@ pub const ChildProcess = struct { |
| 74 | 89 | ||
| 75 | /// First argument in argv is the executable. | 90 | /// First argument in argv is the executable. |
| 76 | /// On success must call deinit. | 91 | /// On success must call deinit. |
| 77 | pub fn init(argv: []const []const u8, allocator: &mem.Allocator) %&ChildProcess { | 92 | pub fn init(argv: []const []const u8, allocator: &mem.Allocator) !&ChildProcess { |
| 78 | const child = try allocator.create(ChildProcess); | 93 | const child = try allocator.create(ChildProcess); |
| 79 | errdefer allocator.destroy(child); | 94 | errdefer allocator.destroy(child); |
| 80 | 95 | ||
| ... | @@ -103,7 +118,7 @@ pub const ChildProcess = struct { | ... | @@ -103,7 +118,7 @@ pub const ChildProcess = struct { |
| 103 | return child; | 118 | return child; |
| 104 | } | 119 | } |
| 105 | 120 | ||
| 106 | pub fn setUserName(self: &ChildProcess, name: []const u8) %void { | 121 | pub fn setUserName(self: &ChildProcess, name: []const u8) !void { |
| 107 | const user_info = try os.getUserInfo(name); | 122 | const user_info = try os.getUserInfo(name); |
| 108 | self.uid = user_info.uid; | 123 | self.uid = user_info.uid; |
| 109 | self.gid = user_info.gid; | 124 | self.gid = user_info.gid; |
| ... | @@ -111,7 +126,7 @@ pub const ChildProcess = struct { | ... | @@ -111,7 +126,7 @@ pub const ChildProcess = struct { |
| 111 | 126 | ||
| 112 | /// onTerm can be called before `spawn` returns. | 127 | /// onTerm can be called before `spawn` returns. |
| 113 | /// On success must call `kill` or `wait`. | 128 | /// On success must call `kill` or `wait`. |
| 114 | pub fn spawn(self: &ChildProcess) %void { | 129 | pub fn spawn(self: &ChildProcess) !void { |
| 115 | if (is_windows) { | 130 | if (is_windows) { |
| 116 | return self.spawnWindows(); | 131 | return self.spawnWindows(); |
| 117 | } else { | 132 | } else { |
| ... | @@ -119,13 +134,13 @@ pub const ChildProcess = struct { | ... | @@ -119,13 +134,13 @@ pub const ChildProcess = struct { |
| 119 | } | 134 | } |
| 120 | } | 135 | } |
| 121 | 136 | ||
| 122 | pub fn spawnAndWait(self: &ChildProcess) %Term { | 137 | pub fn spawnAndWait(self: &ChildProcess) !Term { |
| 123 | try self.spawn(); | 138 | try self.spawn(); |
| 124 | return self.wait(); | 139 | return self.wait(); |
| 125 | } | 140 | } |
| 126 | 141 | ||
| 127 | /// Forcibly terminates child process and then cleans up all resources. | 142 | /// Forcibly terminates child process and then cleans up all resources. |
| 128 | pub fn kill(self: &ChildProcess) %Term { | 143 | pub fn kill(self: &ChildProcess) !Term { |
| 129 | if (is_windows) { | 144 | if (is_windows) { |
| 130 | return self.killWindows(1); | 145 | return self.killWindows(1); |
| 131 | } else { | 146 | } else { |
| ... | @@ -133,7 +148,7 @@ pub const ChildProcess = struct { | ... | @@ -133,7 +148,7 @@ pub const ChildProcess = struct { |
| 133 | } | 148 | } |
| 134 | } | 149 | } |
| 135 | 150 | ||
| 136 | pub fn killWindows(self: &ChildProcess, exit_code: windows.UINT) %Term { | 151 | pub fn killWindows(self: &ChildProcess, exit_code: windows.UINT) !Term { |
| 137 | if (self.term) |term| { | 152 | if (self.term) |term| { |
| 138 | self.cleanupStreams(); | 153 | self.cleanupStreams(); |
| 139 | return term; | 154 | return term; |
| ... | @@ -145,11 +160,11 @@ pub const ChildProcess = struct { | ... | @@ -145,11 +160,11 @@ pub const ChildProcess = struct { |
| 145 | else => os.unexpectedErrorWindows(err), | 160 | else => os.unexpectedErrorWindows(err), |
| 146 | }; | 161 | }; |
| 147 | } | 162 | } |
| 148 | self.waitUnwrappedWindows(); | 163 | try self.waitUnwrappedWindows(); |
| 149 | return ??self.term; | 164 | return ??self.term; |
| 150 | } | 165 | } |
| 151 | 166 | ||
| 152 | pub fn killPosix(self: &ChildProcess) %Term { | 167 | pub fn killPosix(self: &ChildProcess) !Term { |
| 153 | block_SIGCHLD(); | 168 | block_SIGCHLD(); |
| 154 | defer restore_SIGCHLD(); | 169 | defer restore_SIGCHLD(); |
| 155 | 170 | ||
| ... | @@ -172,7 +187,7 @@ pub const ChildProcess = struct { | ... | @@ -172,7 +187,7 @@ pub const ChildProcess = struct { |
| 172 | } | 187 | } |
| 173 | 188 | ||
| 174 | /// Blocks until child process terminates and then cleans up all resources. | 189 | /// Blocks until child process terminates and then cleans up all resources. |
| 175 | pub fn wait(self: &ChildProcess) %Term { | 190 | pub fn wait(self: &ChildProcess) !Term { |
| 176 | if (is_windows) { | 191 | if (is_windows) { |
| 177 | return self.waitWindows(); | 192 | return self.waitWindows(); |
| 178 | } else { | 193 | } else { |
| ... | @@ -189,7 +204,7 @@ pub const ChildProcess = struct { | ... | @@ -189,7 +204,7 @@ pub const ChildProcess = struct { |
| 189 | /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns. | 204 | /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns. |
| 190 | /// If it succeeds, the caller owns result.stdout and result.stderr memory. | 205 | /// If it succeeds, the caller owns result.stdout and result.stderr memory. |
| 191 | pub fn exec(allocator: &mem.Allocator, argv: []const []const u8, cwd: ?[]const u8, | 206 | pub fn exec(allocator: &mem.Allocator, argv: []const []const u8, cwd: ?[]const u8, |
| 192 | env_map: ?&const BufMap, max_output_size: usize) %ExecResult | 207 | env_map: ?&const BufMap, max_output_size: usize) !ExecResult |
| 193 | { | 208 | { |
| 194 | const child = try ChildProcess.init(argv, allocator); | 209 | const child = try ChildProcess.init(argv, allocator); |
| 195 | defer child.deinit(); | 210 | defer child.deinit(); |
| ... | @@ -220,7 +235,7 @@ pub const ChildProcess = struct { | ... | @@ -220,7 +235,7 @@ pub const ChildProcess = struct { |
| 220 | }; | 235 | }; |
| 221 | } | 236 | } |
| 222 | 237 | ||
| 223 | fn waitWindows(self: &ChildProcess) %Term { | 238 | fn waitWindows(self: &ChildProcess) !Term { |
| 224 | if (self.term) |term| { | 239 | if (self.term) |term| { |
| 225 | self.cleanupStreams(); | 240 | self.cleanupStreams(); |
| 226 | return term; | 241 | return term; |
| ... | @@ -230,7 +245,7 @@ pub const ChildProcess = struct { | ... | @@ -230,7 +245,7 @@ pub const ChildProcess = struct { |
| 230 | return ??self.term; | 245 | return ??self.term; |
| 231 | } | 246 | } |
| 232 | 247 | ||
| 233 | fn waitPosix(self: &ChildProcess) %Term { | 248 | fn waitPosix(self: &ChildProcess) !Term { |
| 234 | block_SIGCHLD(); | 249 | block_SIGCHLD(); |
| 235 | defer restore_SIGCHLD(); | 250 | defer restore_SIGCHLD(); |
| 236 | 251 | ||
| ... | @@ -247,10 +262,10 @@ pub const ChildProcess = struct { | ... | @@ -247,10 +262,10 @@ pub const ChildProcess = struct { |
| 247 | self.allocator.destroy(self); | 262 | self.allocator.destroy(self); |
| 248 | } | 263 | } |
| 249 | 264 | ||
| 250 | fn waitUnwrappedWindows(self: &ChildProcess) %void { | 265 | fn waitUnwrappedWindows(self: &ChildProcess) !void { |
| 251 | const result = os.windowsWaitSingle(self.handle, windows.INFINITE); | 266 | const result = os.windowsWaitSingle(self.handle, windows.INFINITE); |
| 252 | 267 | ||
| 253 | self.term = (%Term)(x: { | 268 | self.term = (SpawnError!Term)(x: { |
| 254 | var exit_code: windows.DWORD = undefined; | 269 | var exit_code: windows.DWORD = undefined; |
| 255 | if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) { | 270 | if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) { |
| 256 | break :x Term { .Unknown = 0 }; | 271 | break :x Term { .Unknown = 0 }; |
| ... | @@ -295,7 +310,7 @@ pub const ChildProcess = struct { | ... | @@ -295,7 +310,7 @@ pub const ChildProcess = struct { |
| 295 | if (self.stderr) |*stderr| { stderr.close(); self.stderr = null; } | 310 | if (self.stderr) |*stderr| { stderr.close(); self.stderr = null; } |
| 296 | } | 311 | } |
| 297 | 312 | ||
| 298 | fn cleanupAfterWait(self: &ChildProcess, status: i32) %Term { | 313 | fn cleanupAfterWait(self: &ChildProcess, status: i32) !Term { |
| 299 | children_nodes.remove(&self.llnode); | 314 | children_nodes.remove(&self.llnode); |
| 300 | 315 | ||
| 301 | defer { | 316 | defer { |
| ... | @@ -313,7 +328,7 @@ pub const ChildProcess = struct { | ... | @@ -313,7 +328,7 @@ pub const ChildProcess = struct { |
| 313 | // Here we potentially return the fork child's error | 328 | // Here we potentially return the fork child's error |
| 314 | // from the parent pid. | 329 | // from the parent pid. |
| 315 | if (err_int != @maxValue(ErrInt)) { | 330 | if (err_int != @maxValue(ErrInt)) { |
| 316 | return error(err_int); | 331 | return SpawnError(err_int); |
| 317 | } | 332 | } |
| 318 | 333 | ||
| 319 | return statusToTerm(status); | 334 | return statusToTerm(status); |
| ... | @@ -331,7 +346,7 @@ pub const ChildProcess = struct { | ... | @@ -331,7 +346,7 @@ pub const ChildProcess = struct { |
| 331 | ; | 346 | ; |
| 332 | } | 347 | } |
| 333 | 348 | ||
| 334 | fn spawnPosix(self: &ChildProcess) %void { | 349 | fn spawnPosix(self: &ChildProcess) !void { |
| 335 | // TODO atomically set a flag saying that we already did this | 350 | // TODO atomically set a flag saying that we already did this |
| 336 | install_SIGCHLD_handler(); | 351 | install_SIGCHLD_handler(); |
| 337 | 352 | ||
| ... | @@ -440,7 +455,7 @@ pub const ChildProcess = struct { | ... | @@ -440,7 +455,7 @@ pub const ChildProcess = struct { |
| 440 | if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); } | 455 | if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); } |
| 441 | } | 456 | } |
| 442 | 457 | ||
| 443 | fn spawnWindows(self: &ChildProcess) %void { | 458 | fn spawnWindows(self: &ChildProcess) !void { |
| 444 | const saAttr = windows.SECURITY_ATTRIBUTES { | 459 | const saAttr = windows.SECURITY_ATTRIBUTES { |
| 445 | .nLength = @sizeOf(windows.SECURITY_ATTRIBUTES), | 460 | .nLength = @sizeOf(windows.SECURITY_ATTRIBUTES), |
| 446 | .bInheritHandle = windows.TRUE, | 461 | .bInheritHandle = windows.TRUE, |
| ... | @@ -623,7 +638,7 @@ pub const ChildProcess = struct { | ... | @@ -623,7 +638,7 @@ pub const ChildProcess = struct { |
| 623 | if (self.stdout_behavior == StdIo.Pipe) { os.close(??g_hChildStd_OUT_Wr); } | 638 | if (self.stdout_behavior == StdIo.Pipe) { os.close(??g_hChildStd_OUT_Wr); } |
| 624 | } | 639 | } |
| 625 | 640 | ||
| 626 | fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) %void { | 641 | fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) !void { |
| 627 | switch (stdio) { | 642 | switch (stdio) { |
| 628 | StdIo.Pipe => try os.posixDup2(pipe_fd, std_fileno), | 643 | StdIo.Pipe => try os.posixDup2(pipe_fd, std_fileno), |
| 629 | StdIo.Close => os.close(std_fileno), | 644 | StdIo.Close => os.close(std_fileno), |
| ... | @@ -635,7 +650,7 @@ pub const ChildProcess = struct { | ... | @@ -635,7 +650,7 @@ pub const ChildProcess = struct { |
| 635 | }; | 650 | }; |
| 636 | 651 | ||
| 637 | fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?&u8, | 652 | fn 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 |
| 639 | { | 654 | { |
| 640 | if (windows.CreateProcessA(app_name, cmd_line, null, null, windows.TRUE, 0, | 655 | if (windows.CreateProcessA(app_name, cmd_line, null, null, windows.TRUE, 0, |
| 641 | @ptrCast(?&c_void, envp_ptr), cwd_ptr, lpStartupInfo, lpProcessInformation) == 0) | 656 | @ptrCast(?&c_void, envp_ptr), cwd_ptr, lpStartupInfo, lpProcessInformation) == 0) |
| ... | @@ -655,7 +670,7 @@ fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ? | ... | @@ -655,7 +670,7 @@ fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ? |
| 655 | 670 | ||
| 656 | /// Caller must dealloc. | 671 | /// Caller must dealloc. |
| 657 | /// Guarantees a null byte at result[result.len]. | 672 | /// Guarantees a null byte at result[result.len]. |
| 658 | fn windowsCreateCommandLine(allocator: &mem.Allocator, argv: []const []const u8) %[]u8 { | 673 | fn windowsCreateCommandLine(allocator: &mem.Allocator, argv: []const []const u8) ![]u8 { |
| 659 | var buf = try Buffer.initSize(allocator, 0); | 674 | var buf = try Buffer.initSize(allocator, 0); |
| 660 | defer buf.deinit(); | 675 | defer buf.deinit(); |
| 661 | 676 | ||
| ... | @@ -700,7 +715,7 @@ fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void { | ... | @@ -700,7 +715,7 @@ fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void { |
| 700 | // a namespace field lookup | 715 | // a namespace field lookup |
| 701 | const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES; | 716 | const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES; |
| 702 | 717 | ||
| 703 | fn windowsMakePipe(rd: &windows.HANDLE, wr: &windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) %void { | 718 | fn windowsMakePipe(rd: &windows.HANDLE, wr: &windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) !void { |
| 704 | if (windows.CreatePipe(rd, wr, sattr, 0) == 0) { | 719 | if (windows.CreatePipe(rd, wr, sattr, 0) == 0) { |
| 705 | const err = windows.GetLastError(); | 720 | const err = windows.GetLastError(); |
| 706 | return switch (err) { | 721 | return switch (err) { |
| ... | @@ -709,7 +724,7 @@ fn windowsMakePipe(rd: &windows.HANDLE, wr: &windows.HANDLE, sattr: &const SECUR | ... | @@ -709,7 +724,7 @@ fn windowsMakePipe(rd: &windows.HANDLE, wr: &windows.HANDLE, sattr: &const SECUR |
| 709 | } | 724 | } |
| 710 | } | 725 | } |
| 711 | 726 | ||
| 712 | fn windowsSetHandleInfo(h: windows.HANDLE, mask: windows.DWORD, flags: windows.DWORD) %void { | 727 | fn windowsSetHandleInfo(h: windows.HANDLE, mask: windows.DWORD, flags: windows.DWORD) !void { |
| 713 | if (windows.SetHandleInformation(h, mask, flags) == 0) { | 728 | if (windows.SetHandleInformation(h, mask, flags) == 0) { |
| 714 | const err = windows.GetLastError(); | 729 | const err = windows.GetLastError(); |
| 715 | return switch (err) { | 730 | return switch (err) { |
| ... | @@ -718,7 +733,7 @@ fn windowsSetHandleInfo(h: windows.HANDLE, mask: windows.DWORD, flags: windows.D | ... | @@ -718,7 +733,7 @@ fn windowsSetHandleInfo(h: windows.HANDLE, mask: windows.DWORD, flags: windows.D |
| 718 | } | 733 | } |
| 719 | } | 734 | } |
| 720 | 735 | ||
| 721 | fn windowsMakePipeIn(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) %void { | 736 | fn windowsMakePipeIn(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) !void { |
| 722 | var rd_h: windows.HANDLE = undefined; | 737 | var rd_h: windows.HANDLE = undefined; |
| 723 | var wr_h: windows.HANDLE = undefined; | 738 | var wr_h: windows.HANDLE = undefined; |
| 724 | try windowsMakePipe(&rd_h, &wr_h, sattr); | 739 | try windowsMakePipe(&rd_h, &wr_h, sattr); |
| ... | @@ -728,7 +743,7 @@ fn windowsMakePipeIn(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const S | ... | @@ -728,7 +743,7 @@ fn windowsMakePipeIn(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const S |
| 728 | *wr = wr_h; | 743 | *wr = wr_h; |
| 729 | } | 744 | } |
| 730 | 745 | ||
| 731 | fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) %void { | 746 | fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) !void { |
| 732 | var rd_h: windows.HANDLE = undefined; | 747 | var rd_h: windows.HANDLE = undefined; |
| 733 | var wr_h: windows.HANDLE = undefined; | 748 | var wr_h: windows.HANDLE = undefined; |
| 734 | try windowsMakePipe(&rd_h, &wr_h, sattr); | 749 | try windowsMakePipe(&rd_h, &wr_h, sattr); |
| ... | @@ -738,7 +753,7 @@ fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const | ... | @@ -738,7 +753,7 @@ fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const |
| 738 | *wr = wr_h; | 753 | *wr = wr_h; |
| 739 | } | 754 | } |
| 740 | 755 | ||
| 741 | fn makePipe() %[2]i32 { | 756 | fn makePipe() ![2]i32 { |
| 742 | var fds: [2]i32 = undefined; | 757 | var fds: [2]i32 = undefined; |
| 743 | const err = posix.getErrno(posix.pipe(&fds)); | 758 | const err = posix.getErrno(posix.pipe(&fds)); |
| 744 | if (err > 0) { | 759 | if (err > 0) { |
| ... | @@ -757,20 +772,20 @@ fn destroyPipe(pipe: &const [2]i32) void { | ... | @@ -757,20 +772,20 @@ fn destroyPipe(pipe: &const [2]i32) void { |
| 757 | 772 | ||
| 758 | // Child of fork calls this to report an error to the fork parent. | 773 | // Child of fork calls this to report an error to the fork parent. |
| 759 | // Then the child exits. | 774 | // Then the child exits. |
| 760 | fn forkChildErrReport(fd: i32, err: error) noreturn { | 775 | fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn { |
| 761 | _ = writeIntFd(fd, ErrInt(err)); | 776 | _ = writeIntFd(fd, ErrInt(err)); |
| 762 | posix.exit(1); | 777 | posix.exit(1); |
| 763 | } | 778 | } |
| 764 | 779 | ||
| 765 | const ErrInt = @IntType(false, @sizeOf(error) * 8); | 780 | const ErrInt = @IntType(false, @sizeOf(error) * 8); |
| 766 | 781 | ||
| 767 | fn writeIntFd(fd: i32, value: ErrInt) %void { | 782 | fn writeIntFd(fd: i32, value: ErrInt) !void { |
| 768 | var bytes: [@sizeOf(ErrInt)]u8 = undefined; | 783 | var bytes: [@sizeOf(ErrInt)]u8 = undefined; |
| 769 | mem.writeInt(bytes[0..], value, builtin.endian); | 784 | mem.writeInt(bytes[0..], value, builtin.endian); |
| 770 | os.posixWrite(fd, bytes[0..]) catch return error.SystemResources; | 785 | os.posixWrite(fd, bytes[0..]) catch return error.SystemResources; |
| 771 | } | 786 | } |
| 772 | 787 | ||
| 773 | fn readIntFd(fd: i32) %ErrInt { | 788 | fn readIntFd(fd: i32) !ErrInt { |
| 774 | var bytes: [@sizeOf(ErrInt)]u8 = undefined; | 789 | var bytes: [@sizeOf(ErrInt)]u8 = undefined; |
| 775 | os.posixRead(fd, bytes[0..]) catch return error.SystemResources; | 790 | os.posixRead(fd, bytes[0..]) catch return error.SystemResources; |
| 776 | return mem.readInt(bytes[0..], ErrInt, builtin.endian); | 791 | return mem.readInt(bytes[0..], ErrInt, builtin.endian); |
std/os/get_user_id.zig+2-5| ... | @@ -9,7 +9,7 @@ pub const UserInfo = struct { | ... | @@ -9,7 +9,7 @@ pub const UserInfo = struct { |
| 9 | }; | 9 | }; |
| 10 | 10 | ||
| 11 | /// POSIX function which gets a uid from username. | 11 | /// POSIX function which gets a uid from username. |
| 12 | pub fn getUserInfo(name: []const u8) %UserInfo { | 12 | pub fn getUserInfo(name: []const u8) !UserInfo { |
| 13 | return switch (builtin.os) { | 13 | return switch (builtin.os) { |
| 14 | Os.linux, Os.macosx, Os.ios => posixGetUserInfo(name), | 14 | Os.linux, Os.macosx, Os.ios => posixGetUserInfo(name), |
| 15 | else => @compileError("Unsupported OS"), | 15 | else => @compileError("Unsupported OS"), |
| ... | @@ -24,13 +24,10 @@ const State = enum { | ... | @@ -24,13 +24,10 @@ const State = enum { |
| 24 | ReadGroupId, | 24 | ReadGroupId, |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | error UserNotFound; | ||
| 28 | error CorruptPasswordFile; | ||
| 29 | |||
| 30 | // TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else | 27 | // TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else |
| 31 | // like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`. | 28 | // like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`. |
| 32 | 29 | ||
| 33 | pub fn posixGetUserInfo(name: []const u8) %UserInfo { | 30 | pub fn posixGetUserInfo(name: []const u8) !UserInfo { |
| 34 | var in_stream = try io.InStream.open("/etc/passwd", null); | 31 | var in_stream = try io.InStream.open("/etc/passwd", null); |
| 35 | defer in_stream.close(); | 32 | defer in_stream.close(); |
| 36 | 33 |
std/os/index.zig+207-118| ... | @@ -38,6 +38,10 @@ pub const windowsLoadDll = windows_util.windowsLoadDll; | ... | @@ -38,6 +38,10 @@ pub const windowsLoadDll = windows_util.windowsLoadDll; |
| 38 | pub const windowsUnloadDll = windows_util.windowsUnloadDll; | 38 | pub const windowsUnloadDll = windows_util.windowsUnloadDll; |
| 39 | pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock; | 39 | pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock; |
| 40 | 40 | ||
| 41 | pub const WindowsWaitError = windows_util.WaitError; | ||
| 42 | pub const WindowsOpenError = windows_util.OpenError; | ||
| 43 | pub const WindowsWriteError = windows_util.WriteError; | ||
| 44 | |||
| 41 | pub const FileHandle = if (is_windows) windows.HANDLE else i32; | 45 | pub const FileHandle = if (is_windows) windows.HANDLE else i32; |
| 42 | 46 | ||
| 43 | const debug = std.debug; | 47 | const debug = std.debug; |
| ... | @@ -57,25 +61,10 @@ const ArrayList = std.ArrayList; | ... | @@ -57,25 +61,10 @@ const ArrayList = std.ArrayList; |
| 57 | const Buffer = std.Buffer; | 61 | const Buffer = std.Buffer; |
| 58 | const math = std.math; | 62 | const math = std.math; |
| 59 | 63 | ||
| 60 | error SystemResources; | ||
| 61 | error AccessDenied; | ||
| 62 | error InvalidExe; | ||
| 63 | error FileSystem; | ||
| 64 | error IsDir; | ||
| 65 | error FileNotFound; | ||
| 66 | error FileBusy; | ||
| 67 | error PathAlreadyExists; | ||
| 68 | error SymLinkLoop; | ||
| 69 | error ReadOnlyFileSystem; | ||
| 70 | error LinkQuotaExceeded; | ||
| 71 | error RenameAcrossMountPoints; | ||
| 72 | error DirNotEmpty; | ||
| 73 | error WouldBlock; | ||
| 74 | |||
| 75 | /// Fills `buf` with random bytes. If linking against libc, this calls the | 64 | /// Fills `buf` with random bytes. If linking against libc, this calls the |
| 76 | /// appropriate OS-specific library call. Otherwise it uses the zig standard | 65 | /// appropriate OS-specific library call. Otherwise it uses the zig standard |
| 77 | /// library implementation. | 66 | /// library implementation. |
| 78 | pub fn getRandomBytes(buf: []u8) %void { | 67 | pub fn getRandomBytes(buf: []u8) !void { |
| 79 | switch (builtin.os) { | 68 | switch (builtin.os) { |
| 80 | Os.linux => while (true) { | 69 | Os.linux => while (true) { |
| 81 | // TODO check libc version and potentially call c.getrandom. | 70 | // TODO check libc version and potentially call c.getrandom. |
| ... | @@ -188,7 +177,7 @@ pub fn close(handle: FileHandle) void { | ... | @@ -188,7 +177,7 @@ pub fn close(handle: FileHandle) void { |
| 188 | } | 177 | } |
| 189 | 178 | ||
| 190 | /// Calls POSIX read, and keeps trying if it gets interrupted. | 179 | /// Calls POSIX read, and keeps trying if it gets interrupted. |
| 191 | pub fn posixRead(fd: i32, buf: []u8) %void { | 180 | pub fn posixRead(fd: i32, buf: []u8) !void { |
| 192 | // Linux can return EINVAL when read amount is > 0x7ffff000 | 181 | // Linux can return EINVAL when read amount is > 0x7ffff000 |
| 193 | // See https://github.com/zig-lang/zig/pull/743#issuecomment-363158274 | 182 | // See https://github.com/zig-lang/zig/pull/743#issuecomment-363158274 |
| 194 | const max_buf_len = 0x7ffff000; | 183 | const max_buf_len = 0x7ffff000; |
| ... | @@ -214,17 +203,21 @@ pub fn posixRead(fd: i32, buf: []u8) %void { | ... | @@ -214,17 +203,21 @@ pub fn posixRead(fd: i32, buf: []u8) %void { |
| 214 | } | 203 | } |
| 215 | } | 204 | } |
| 216 | 205 | ||
| 217 | error WouldBlock; | 206 | pub const PosixWriteError = error { |
| 218 | error FileClosed; | 207 | WouldBlock, |
| 219 | error DestinationAddressRequired; | 208 | FileClosed, |
| 220 | error DiskQuota; | 209 | DestinationAddressRequired, |
| 221 | error FileTooBig; | 210 | DiskQuota, |
| 222 | error InputOutput; | 211 | FileTooBig, |
| 223 | error NoSpaceLeft; | 212 | InputOutput, |
| 224 | error BrokenPipe; | 213 | NoSpaceLeft, |
| 214 | AccessDenied, | ||
| 215 | BrokenPipe, | ||
| 216 | Unexpected, | ||
| 217 | }; | ||
| 225 | 218 | ||
| 226 | /// Calls POSIX write, and keeps trying if it gets interrupted. | 219 | /// Calls POSIX write, and keeps trying if it gets interrupted. |
| 227 | pub fn posixWrite(fd: i32, bytes: []const u8) %void { | 220 | pub fn posixWrite(fd: i32, bytes: []const u8) !void { |
| 228 | // Linux can return EINVAL when write amount is > 0x7ffff000 | 221 | // Linux can return EINVAL when write amount is > 0x7ffff000 |
| 229 | // See https://github.com/zig-lang/zig/pull/743#issuecomment-363165856 | 222 | // See https://github.com/zig-lang/zig/pull/743#issuecomment-363165856 |
| 230 | const max_bytes_len = 0x7ffff000; | 223 | const max_bytes_len = 0x7ffff000; |
| ... | @@ -238,15 +231,15 @@ pub fn posixWrite(fd: i32, bytes: []const u8) %void { | ... | @@ -238,15 +231,15 @@ pub fn posixWrite(fd: i32, bytes: []const u8) %void { |
| 238 | return switch (write_err) { | 231 | return switch (write_err) { |
| 239 | posix.EINTR => continue, | 232 | posix.EINTR => continue, |
| 240 | posix.EINVAL, posix.EFAULT => unreachable, | 233 | posix.EINVAL, posix.EFAULT => unreachable, |
| 241 | posix.EAGAIN => error.WouldBlock, | 234 | posix.EAGAIN => PosixWriteError.WouldBlock, |
| 242 | posix.EBADF => error.FileClosed, | 235 | posix.EBADF => PosixWriteError.FileClosed, |
| 243 | posix.EDESTADDRREQ => error.DestinationAddressRequired, | 236 | posix.EDESTADDRREQ => PosixWriteError.DestinationAddressRequired, |
| 244 | posix.EDQUOT => error.DiskQuota, | 237 | posix.EDQUOT => PosixWriteError.DiskQuota, |
| 245 | posix.EFBIG => error.FileTooBig, | 238 | posix.EFBIG => PosixWriteError.FileTooBig, |
| 246 | posix.EIO => error.InputOutput, | 239 | posix.EIO => PosixWriteError.InputOutput, |
| 247 | posix.ENOSPC => error.NoSpaceLeft, | 240 | posix.ENOSPC => PosixWriteError.NoSpaceLeft, |
| 248 | posix.EPERM => error.AccessDenied, | 241 | posix.EPERM => PosixWriteError.AccessDenied, |
| 249 | posix.EPIPE => error.BrokenPipe, | 242 | posix.EPIPE => PosixWriteError.BrokenPipe, |
| 250 | else => unexpectedErrorPosix(write_err), | 243 | else => unexpectedErrorPosix(write_err), |
| 251 | }; | 244 | }; |
| 252 | } | 245 | } |
| ... | @@ -254,13 +247,31 @@ pub fn posixWrite(fd: i32, bytes: []const u8) %void { | ... | @@ -254,13 +247,31 @@ pub fn posixWrite(fd: i32, bytes: []const u8) %void { |
| 254 | } | 247 | } |
| 255 | } | 248 | } |
| 256 | 249 | ||
| 250 | pub const PosixOpenError = error { | ||
| 251 | OutOfMemory, | ||
| 252 | AccessDenied, | ||
| 253 | FileTooBig, | ||
| 254 | IsDir, | ||
| 255 | SymLinkLoop, | ||
| 256 | ProcessFdQuotaExceeded, | ||
| 257 | NameTooLong, | ||
| 258 | SystemFdQuotaExceeded, | ||
| 259 | NoDevice, | ||
| 260 | PathNotFound, | ||
| 261 | SystemResources, | ||
| 262 | NoSpaceLeft, | ||
| 263 | NotDir, | ||
| 264 | PathAlreadyExists, | ||
| 265 | Unexpected, | ||
| 266 | }; | ||
| 267 | |||
| 257 | /// ::file_path may need to be copied in memory to add a null terminating byte. In this case | 268 | /// ::file_path may need to be copied in memory to add a null terminating byte. In this case |
| 258 | /// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed | 269 | /// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed |
| 259 | /// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned. | 270 | /// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned. |
| 260 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. | 271 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. |
| 261 | /// Calls POSIX open, keeps trying if it gets interrupted, and translates | 272 | /// Calls POSIX open, keeps trying if it gets interrupted, and translates |
| 262 | /// the return value into zig errors. | 273 | /// the return value into zig errors. |
| 263 | pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Allocator) %i32 { | 274 | pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Allocator) PosixOpenError!i32 { |
| 264 | var stack_buf: [max_noalloc_path_len]u8 = undefined; | 275 | var stack_buf: [max_noalloc_path_len]u8 = undefined; |
| 265 | var path0: []u8 = undefined; | 276 | var path0: []u8 = undefined; |
| 266 | var need_free = false; | 277 | var need_free = false; |
| ... | @@ -282,7 +293,7 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al | ... | @@ -282,7 +293,7 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al |
| 282 | return posixOpenC(path0.ptr, flags, perm); | 293 | return posixOpenC(path0.ptr, flags, perm); |
| 283 | } | 294 | } |
| 284 | 295 | ||
| 285 | pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) %i32 { | 296 | pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) !i32 { |
| 286 | while (true) { | 297 | while (true) { |
| 287 | const result = posix.open(file_path, flags, perm); | 298 | const result = posix.open(file_path, flags, perm); |
| 288 | const err = posix.getErrno(result); | 299 | const err = posix.getErrno(result); |
| ... | @@ -292,20 +303,20 @@ pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) %i32 { | ... | @@ -292,20 +303,20 @@ pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) %i32 { |
| 292 | 303 | ||
| 293 | posix.EFAULT => unreachable, | 304 | posix.EFAULT => unreachable, |
| 294 | posix.EINVAL => unreachable, | 305 | posix.EINVAL => unreachable, |
| 295 | posix.EACCES => error.AccessDenied, | 306 | posix.EACCES => PosixOpenError.AccessDenied, |
| 296 | posix.EFBIG, posix.EOVERFLOW => error.FileTooBig, | 307 | posix.EFBIG, posix.EOVERFLOW => PosixOpenError.FileTooBig, |
| 297 | posix.EISDIR => error.IsDir, | 308 | posix.EISDIR => PosixOpenError.IsDir, |
| 298 | posix.ELOOP => error.SymLinkLoop, | 309 | posix.ELOOP => PosixOpenError.SymLinkLoop, |
| 299 | posix.EMFILE => error.ProcessFdQuotaExceeded, | 310 | posix.EMFILE => PosixOpenError.ProcessFdQuotaExceeded, |
| 300 | posix.ENAMETOOLONG => error.NameTooLong, | 311 | posix.ENAMETOOLONG => PosixOpenError.NameTooLong, |
| 301 | posix.ENFILE => error.SystemFdQuotaExceeded, | 312 | posix.ENFILE => PosixOpenError.SystemFdQuotaExceeded, |
| 302 | posix.ENODEV => error.NoDevice, | 313 | posix.ENODEV => PosixOpenError.NoDevice, |
| 303 | posix.ENOENT => error.PathNotFound, | 314 | posix.ENOENT => PosixOpenError.PathNotFound, |
| 304 | posix.ENOMEM => error.SystemResources, | 315 | posix.ENOMEM => PosixOpenError.SystemResources, |
| 305 | posix.ENOSPC => error.NoSpaceLeft, | 316 | posix.ENOSPC => PosixOpenError.NoSpaceLeft, |
| 306 | posix.ENOTDIR => error.NotDir, | 317 | posix.ENOTDIR => PosixOpenError.NotDir, |
| 307 | posix.EPERM => error.AccessDenied, | 318 | posix.EPERM => PosixOpenError.AccessDenied, |
| 308 | posix.EEXIST => error.PathAlreadyExists, | 319 | posix.EEXIST => PosixOpenError.PathAlreadyExists, |
| 309 | else => unexpectedErrorPosix(err), | 320 | else => unexpectedErrorPosix(err), |
| 310 | }; | 321 | }; |
| 311 | } | 322 | } |
| ... | @@ -313,7 +324,7 @@ pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) %i32 { | ... | @@ -313,7 +324,7 @@ pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) %i32 { |
| 313 | } | 324 | } |
| 314 | } | 325 | } |
| 315 | 326 | ||
| 316 | pub fn posixDup2(old_fd: i32, new_fd: i32) %void { | 327 | pub fn posixDup2(old_fd: i32, new_fd: i32) !void { |
| 317 | while (true) { | 328 | while (true) { |
| 318 | const err = posix.getErrno(posix.dup2(old_fd, new_fd)); | 329 | const err = posix.getErrno(posix.dup2(old_fd, new_fd)); |
| 319 | if (err > 0) { | 330 | if (err > 0) { |
| ... | @@ -328,7 +339,7 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) %void { | ... | @@ -328,7 +339,7 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) %void { |
| 328 | } | 339 | } |
| 329 | } | 340 | } |
| 330 | 341 | ||
| 331 | pub fn createNullDelimitedEnvMap(allocator: &Allocator, env_map: &const BufMap) %[]?&u8 { | 342 | pub fn createNullDelimitedEnvMap(allocator: &Allocator, env_map: &const BufMap) ![]?&u8 { |
| 332 | const envp_count = env_map.count(); | 343 | const envp_count = env_map.count(); |
| 333 | const envp_buf = try allocator.alloc(?&u8, envp_count + 1); | 344 | const envp_buf = try allocator.alloc(?&u8, envp_count + 1); |
| 334 | mem.set(?&u8, envp_buf, null); | 345 | mem.set(?&u8, envp_buf, null); |
| ... | @@ -365,7 +376,7 @@ pub fn freeNullDelimitedEnvMap(allocator: &Allocator, envp_buf: []?&u8) void { | ... | @@ -365,7 +376,7 @@ pub fn freeNullDelimitedEnvMap(allocator: &Allocator, envp_buf: []?&u8) void { |
| 365 | /// `argv[0]` is the executable path. | 376 | /// `argv[0]` is the executable path. |
| 366 | /// This function also uses the PATH environment variable to get the full path to the executable. | 377 | /// This function also uses the PATH environment variable to get the full path to the executable. |
| 367 | pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap, | 378 | pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap, |
| 368 | allocator: &Allocator) %void | 379 | allocator: &Allocator) !void |
| 369 | { | 380 | { |
| 370 | const argv_buf = try allocator.alloc(?&u8, argv.len + 1); | 381 | const argv_buf = try allocator.alloc(?&u8, argv.len + 1); |
| 371 | mem.set(?&u8, argv_buf, null); | 382 | mem.set(?&u8, argv_buf, null); |
| ... | @@ -421,7 +432,19 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap, | ... | @@ -421,7 +432,19 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap, |
| 421 | return posixExecveErrnoToErr(err); | 432 | return posixExecveErrnoToErr(err); |
| 422 | } | 433 | } |
| 423 | 434 | ||
| 424 | fn posixExecveErrnoToErr(err: usize) error { | 435 | pub const PosixExecveError = error { |
| 436 | SystemResources, | ||
| 437 | AccessDenied, | ||
| 438 | InvalidExe, | ||
| 439 | FileSystem, | ||
| 440 | IsDir, | ||
| 441 | FileNotFound, | ||
| 442 | NotDir, | ||
| 443 | FileBusy, | ||
| 444 | Unexpected, | ||
| 445 | }; | ||
| 446 | |||
| 447 | fn posixExecveErrnoToErr(err: usize) PosixExecveError { | ||
| 425 | assert(err > 0); | 448 | assert(err > 0); |
| 426 | return switch (err) { | 449 | return switch (err) { |
| 427 | posix.EFAULT => unreachable, | 450 | posix.EFAULT => unreachable, |
| ... | @@ -440,7 +463,7 @@ fn posixExecveErrnoToErr(err: usize) error { | ... | @@ -440,7 +463,7 @@ fn posixExecveErrnoToErr(err: usize) error { |
| 440 | pub var posix_environ_raw: []&u8 = undefined; | 463 | pub var posix_environ_raw: []&u8 = undefined; |
| 441 | 464 | ||
| 442 | /// Caller must free result when done. | 465 | /// Caller must free result when done. |
| 443 | pub fn getEnvMap(allocator: &Allocator) %BufMap { | 466 | pub fn getEnvMap(allocator: &Allocator) !BufMap { |
| 444 | var result = BufMap.init(allocator); | 467 | var result = BufMap.init(allocator); |
| 445 | errdefer result.deinit(); | 468 | errdefer result.deinit(); |
| 446 | 469 | ||
| ... | @@ -501,10 +524,8 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 { | ... | @@ -501,10 +524,8 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 { |
| 501 | return null; | 524 | return null; |
| 502 | } | 525 | } |
| 503 | 526 | ||
| 504 | error EnvironmentVariableNotFound; | ||
| 505 | |||
| 506 | /// Caller must free returned memory. | 527 | /// Caller must free returned memory. |
| 507 | pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) %[]u8 { | 528 | pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) ![]u8 { |
| 508 | if (is_windows) { | 529 | if (is_windows) { |
| 509 | const key_with_null = try cstr.addNullByte(allocator, key); | 530 | const key_with_null = try cstr.addNullByte(allocator, key); |
| 510 | defer allocator.free(key_with_null); | 531 | defer allocator.free(key_with_null); |
| ... | @@ -538,7 +559,7 @@ pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) %[]u8 { | ... | @@ -538,7 +559,7 @@ pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) %[]u8 { |
| 538 | } | 559 | } |
| 539 | 560 | ||
| 540 | /// Caller must free the returned memory. | 561 | /// Caller must free the returned memory. |
| 541 | pub fn getCwd(allocator: &Allocator) %[]u8 { | 562 | pub fn getCwd(allocator: &Allocator) ![]u8 { |
| 542 | switch (builtin.os) { | 563 | switch (builtin.os) { |
| 543 | Os.windows => { | 564 | Os.windows => { |
| 544 | var buf = try allocator.alloc(u8, 256); | 565 | var buf = try allocator.alloc(u8, 256); |
| ... | @@ -585,7 +606,9 @@ test "os.getCwd" { | ... | @@ -585,7 +606,9 @@ test "os.getCwd" { |
| 585 | _ = getCwd(debug.global_allocator); | 606 | _ = getCwd(debug.global_allocator); |
| 586 | } | 607 | } |
| 587 | 608 | ||
| 588 | pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) %void { | 609 | pub const SymLinkError = PosixSymLinkError || WindowsSymLinkError; |
| 610 | |||
| 611 | pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) SymLinkError!void { | ||
| 589 | if (is_windows) { | 612 | if (is_windows) { |
| 590 | return symLinkWindows(allocator, existing_path, new_path); | 613 | return symLinkWindows(allocator, existing_path, new_path); |
| 591 | } else { | 614 | } else { |
| ... | @@ -593,7 +616,12 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con | ... | @@ -593,7 +616,12 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con |
| 593 | } | 616 | } |
| 594 | } | 617 | } |
| 595 | 618 | ||
| 596 | pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) %void { | 619 | pub const WindowsSymLinkError = error { |
| 620 | OutOfMemory, | ||
| 621 | Unexpected, | ||
| 622 | }; | ||
| 623 | |||
| 624 | pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) WindowsSymLinkError!void { | ||
| 597 | const existing_with_null = try cstr.addNullByte(allocator, existing_path); | 625 | const existing_with_null = try cstr.addNullByte(allocator, existing_path); |
| 598 | defer allocator.free(existing_with_null); | 626 | defer allocator.free(existing_with_null); |
| 599 | const new_with_null = try cstr.addNullByte(allocator, new_path); | 627 | const new_with_null = try cstr.addNullByte(allocator, new_path); |
| ... | @@ -607,7 +635,23 @@ pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path | ... | @@ -607,7 +635,23 @@ pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path |
| 607 | } | 635 | } |
| 608 | } | 636 | } |
| 609 | 637 | ||
| 610 | pub fn symLinkPosix(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) %void { | 638 | pub 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 | |||
| 654 | pub fn symLinkPosix(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) PosixSymLinkError!void { | ||
| 611 | const full_buf = try allocator.alloc(u8, existing_path.len + new_path.len + 2); | 655 | const full_buf = try allocator.alloc(u8, existing_path.len + new_path.len + 2); |
| 612 | defer allocator.free(full_buf); | 656 | defer allocator.free(full_buf); |
| 613 | 657 | ||
| ... | @@ -644,7 +688,7 @@ const b64_fs_encoder = base64.Base64Encoder.init( | ... | @@ -644,7 +688,7 @@ const b64_fs_encoder = base64.Base64Encoder.init( |
| 644 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", | 688 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", |
| 645 | base64.standard_pad_char); | 689 | base64.standard_pad_char); |
| 646 | 690 | ||
| 647 | pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) %void { | 691 | pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) !void { |
| 648 | if (symLink(allocator, existing_path, new_path)) { | 692 | if (symLink(allocator, existing_path, new_path)) { |
| 649 | return; | 693 | return; |
| 650 | } else |err| { | 694 | } else |err| { |
| ... | @@ -673,7 +717,7 @@ pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: | ... | @@ -673,7 +717,7 @@ pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: |
| 673 | 717 | ||
| 674 | } | 718 | } |
| 675 | 719 | ||
| 676 | pub fn deleteFile(allocator: &Allocator, file_path: []const u8) %void { | 720 | pub fn deleteFile(allocator: &Allocator, file_path: []const u8) !void { |
| 677 | if (builtin.os == Os.windows) { | 721 | if (builtin.os == Os.windows) { |
| 678 | return deleteFileWindows(allocator, file_path); | 722 | return deleteFileWindows(allocator, file_path); |
| 679 | } else { | 723 | } else { |
| ... | @@ -681,10 +725,7 @@ pub fn deleteFile(allocator: &Allocator, file_path: []const u8) %void { | ... | @@ -681,10 +725,7 @@ pub fn deleteFile(allocator: &Allocator, file_path: []const u8) %void { |
| 681 | } | 725 | } |
| 682 | } | 726 | } |
| 683 | 727 | ||
| 684 | error FileNotFound; | 728 | pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) !void { |
| 685 | error AccessDenied; | ||
| 686 | |||
| 687 | pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) %void { | ||
| 688 | const buf = try allocator.alloc(u8, file_path.len + 1); | 729 | const buf = try allocator.alloc(u8, file_path.len + 1); |
| 689 | defer allocator.free(buf); | 730 | defer allocator.free(buf); |
| 690 | 731 | ||
| ... | @@ -702,7 +743,7 @@ pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) %void { | ... | @@ -702,7 +743,7 @@ pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) %void { |
| 702 | } | 743 | } |
| 703 | } | 744 | } |
| 704 | 745 | ||
| 705 | pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) %void { | 746 | pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) !void { |
| 706 | const buf = try allocator.alloc(u8, file_path.len + 1); | 747 | const buf = try allocator.alloc(u8, file_path.len + 1); |
| 707 | defer allocator.free(buf); | 748 | defer allocator.free(buf); |
| 708 | 749 | ||
| ... | @@ -729,13 +770,13 @@ pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) %void { | ... | @@ -729,13 +770,13 @@ pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) %void { |
| 729 | } | 770 | } |
| 730 | 771 | ||
| 731 | /// Calls ::copyFileMode with 0o666 for the mode. | 772 | /// Calls ::copyFileMode with 0o666 for the mode. |
| 732 | pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []const u8) %void { | 773 | pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []const u8) !void { |
| 733 | return copyFileMode(allocator, source_path, dest_path, 0o666); | 774 | return copyFileMode(allocator, source_path, dest_path, 0o666); |
| 734 | } | 775 | } |
| 735 | 776 | ||
| 736 | // TODO instead of accepting a mode argument, use the mode from fstat'ing the source path once open | 777 | // TODO instead of accepting a mode argument, use the mode from fstat'ing the source path once open |
| 737 | /// Guaranteed to be atomic. | 778 | /// Guaranteed to be atomic. |
| 738 | pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: []const u8, mode: usize) %void { | 779 | pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: []const u8, mode: usize) !void { |
| 739 | var rand_buf: [12]u8 = undefined; | 780 | var rand_buf: [12]u8 = undefined; |
| 740 | const tmp_path = try allocator.alloc(u8, dest_path.len + base64.Base64Encoder.calcSize(rand_buf.len)); | 781 | const tmp_path = try allocator.alloc(u8, dest_path.len + base64.Base64Encoder.calcSize(rand_buf.len)); |
| 741 | defer allocator.free(tmp_path); | 782 | defer allocator.free(tmp_path); |
| ... | @@ -759,7 +800,7 @@ pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: [ | ... | @@ -759,7 +800,7 @@ pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: [ |
| 759 | } | 800 | } |
| 760 | } | 801 | } |
| 761 | 802 | ||
| 762 | pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8) %void { | 803 | pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8) !void { |
| 763 | const full_buf = try allocator.alloc(u8, old_path.len + new_path.len + 2); | 804 | const full_buf = try allocator.alloc(u8, old_path.len + new_path.len + 2); |
| 764 | defer allocator.free(full_buf); | 805 | defer allocator.free(full_buf); |
| 765 | 806 | ||
| ... | @@ -804,7 +845,7 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8) | ... | @@ -804,7 +845,7 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8) |
| 804 | } | 845 | } |
| 805 | } | 846 | } |
| 806 | 847 | ||
| 807 | pub fn makeDir(allocator: &Allocator, dir_path: []const u8) %void { | 848 | pub fn makeDir(allocator: &Allocator, dir_path: []const u8) !void { |
| 808 | if (is_windows) { | 849 | if (is_windows) { |
| 809 | return makeDirWindows(allocator, dir_path); | 850 | return makeDirWindows(allocator, dir_path); |
| 810 | } else { | 851 | } else { |
| ... | @@ -812,7 +853,7 @@ pub fn makeDir(allocator: &Allocator, dir_path: []const u8) %void { | ... | @@ -812,7 +853,7 @@ pub fn makeDir(allocator: &Allocator, dir_path: []const u8) %void { |
| 812 | } | 853 | } |
| 813 | } | 854 | } |
| 814 | 855 | ||
| 815 | pub fn makeDirWindows(allocator: &Allocator, dir_path: []const u8) %void { | 856 | pub fn makeDirWindows(allocator: &Allocator, dir_path: []const u8) !void { |
| 816 | const path_buf = try cstr.addNullByte(allocator, dir_path); | 857 | const path_buf = try cstr.addNullByte(allocator, dir_path); |
| 817 | defer allocator.free(path_buf); | 858 | defer allocator.free(path_buf); |
| 818 | 859 | ||
| ... | @@ -826,7 +867,7 @@ pub fn makeDirWindows(allocator: &Allocator, dir_path: []const u8) %void { | ... | @@ -826,7 +867,7 @@ pub fn makeDirWindows(allocator: &Allocator, dir_path: []const u8) %void { |
| 826 | } | 867 | } |
| 827 | } | 868 | } |
| 828 | 869 | ||
| 829 | pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) %void { | 870 | pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) !void { |
| 830 | const path_buf = try cstr.addNullByte(allocator, dir_path); | 871 | const path_buf = try cstr.addNullByte(allocator, dir_path); |
| 831 | defer allocator.free(path_buf); | 872 | defer allocator.free(path_buf); |
| 832 | 873 | ||
| ... | @@ -852,7 +893,7 @@ pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) %void { | ... | @@ -852,7 +893,7 @@ pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) %void { |
| 852 | 893 | ||
| 853 | /// Calls makeDir recursively to make an entire path. Returns success if the path | 894 | /// Calls makeDir recursively to make an entire path. Returns success if the path |
| 854 | /// already exists and is a directory. | 895 | /// already exists and is a directory. |
| 855 | pub fn makePath(allocator: &Allocator, full_path: []const u8) %void { | 896 | pub fn makePath(allocator: &Allocator, full_path: []const u8) !void { |
| 856 | const resolved_path = try path.resolve(allocator, full_path); | 897 | const resolved_path = try path.resolve(allocator, full_path); |
| 857 | defer allocator.free(resolved_path); | 898 | defer allocator.free(resolved_path); |
| 858 | 899 | ||
| ... | @@ -890,7 +931,7 @@ pub fn makePath(allocator: &Allocator, full_path: []const u8) %void { | ... | @@ -890,7 +931,7 @@ pub fn makePath(allocator: &Allocator, full_path: []const u8) %void { |
| 890 | 931 | ||
| 891 | /// Returns ::error.DirNotEmpty if the directory is not empty. | 932 | /// Returns ::error.DirNotEmpty if the directory is not empty. |
| 892 | /// To delete a directory recursively, see ::deleteTree | 933 | /// To delete a directory recursively, see ::deleteTree |
| 893 | pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) %void { | 934 | pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) !void { |
| 894 | const path_buf = try allocator.alloc(u8, dir_path.len + 1); | 935 | const path_buf = try allocator.alloc(u8, dir_path.len + 1); |
| 895 | defer allocator.free(path_buf); | 936 | defer allocator.free(path_buf); |
| 896 | 937 | ||
| ... | @@ -919,24 +960,68 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) %void { | ... | @@ -919,24 +960,68 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) %void { |
| 919 | /// removes it. If it cannot be removed because it is a non-empty directory, | 960 | /// removes it. If it cannot be removed because it is a non-empty directory, |
| 920 | /// this function recursively removes its entries and then tries again. | 961 | /// this function recursively removes its entries and then tries again. |
| 921 | // TODO non-recursive implementation | 962 | // TODO non-recursive implementation |
| 922 | pub fn deleteTree(allocator: &Allocator, full_path: []const u8) %void { | 963 | const 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 | }; | ||
| 985 | pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!void { | ||
| 923 | start_over: while (true) { | 986 | start_over: while (true) { |
| 924 | // First, try deleting the item as a file. This way we don't follow sym links. | 987 | // First, try deleting the item as a file. This way we don't follow sym links. |
| 925 | if (deleteFile(allocator, full_path)) { | 988 | if (deleteFile(allocator, full_path)) { |
| 926 | return; | 989 | return; |
| 927 | } else |err| { | 990 | } else |err| switch (err) { |
| 928 | if (err == error.FileNotFound) | 991 | error.FileNotFound => return, |
| 929 | return; | 992 | error.IsDir => {}, |
| 930 | if (err != error.IsDir) | 993 | |
| 931 | return err; | 994 | error.OutOfMemory, |
| 995 | error.AccessDenied, | ||
| 996 | error.SymLinkLoop, | ||
| 997 | error.NameTooLong, | ||
| 998 | error.SystemResources, | ||
| 999 | error.ReadOnlyFileSystem, | ||
| 1000 | error.NotDir, | ||
| 1001 | error.FileSystem, | ||
| 1002 | error.FileBusy, | ||
| 1003 | error.Unexpected | ||
| 1004 | => return err, | ||
| 932 | } | 1005 | } |
| 933 | { | 1006 | { |
| 934 | var dir = Dir.open(allocator, full_path) catch |err| { | 1007 | var dir = Dir.open(allocator, full_path) catch |err| switch (err) { |
| 935 | if (err == error.FileNotFound) | 1008 | error.NotDir => continue :start_over, |
| 936 | return; | 1009 | |
| 937 | if (err == error.NotDir) | 1010 | error.OutOfMemory, |
| 938 | continue :start_over; | 1011 | error.AccessDenied, |
| 939 | return err; | 1012 | error.FileTooBig, |
| 1013 | error.IsDir, | ||
| 1014 | error.SymLinkLoop, | ||
| 1015 | error.ProcessFdQuotaExceeded, | ||
| 1016 | error.NameTooLong, | ||
| 1017 | error.SystemFdQuotaExceeded, | ||
| 1018 | error.NoDevice, | ||
| 1019 | error.PathNotFound, | ||
| 1020 | error.SystemResources, | ||
| 1021 | error.NoSpaceLeft, | ||
| 1022 | error.PathAlreadyExists, | ||
| 1023 | error.Unexpected | ||
| 1024 | => return err, | ||
| 940 | }; | 1025 | }; |
| 941 | defer dir.close(); | 1026 | defer dir.close(); |
| 942 | 1027 | ||
| ... | @@ -988,7 +1073,7 @@ pub const Dir = struct { | ... | @@ -988,7 +1073,7 @@ pub const Dir = struct { |
| 988 | }; | 1073 | }; |
| 989 | }; | 1074 | }; |
| 990 | 1075 | ||
| 991 | pub fn open(allocator: &Allocator, dir_path: []const u8) %Dir { | 1076 | pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir { |
| 992 | const fd = try posixOpen(dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0, allocator); | 1077 | const fd = try posixOpen(dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0, allocator); |
| 993 | return Dir { | 1078 | return Dir { |
| 994 | .allocator = allocator, | 1079 | .allocator = allocator, |
| ... | @@ -1006,7 +1091,7 @@ pub const Dir = struct { | ... | @@ -1006,7 +1091,7 @@ pub const Dir = struct { |
| 1006 | 1091 | ||
| 1007 | /// Memory such as file names referenced in this returned entry becomes invalid | 1092 | /// Memory such as file names referenced in this returned entry becomes invalid |
| 1008 | /// with subsequent calls to next, as well as when this ::Dir is deinitialized. | 1093 | /// with subsequent calls to next, as well as when this ::Dir is deinitialized. |
| 1009 | pub fn next(self: &Dir) %?Entry { | 1094 | pub fn next(self: &Dir) !?Entry { |
| 1010 | start_over: while (true) { | 1095 | start_over: while (true) { |
| 1011 | if (self.index >= self.end_index) { | 1096 | if (self.index >= self.end_index) { |
| 1012 | if (self.buf.len == 0) { | 1097 | if (self.buf.len == 0) { |
| ... | @@ -1063,7 +1148,7 @@ pub const Dir = struct { | ... | @@ -1063,7 +1148,7 @@ pub const Dir = struct { |
| 1063 | } | 1148 | } |
| 1064 | }; | 1149 | }; |
| 1065 | 1150 | ||
| 1066 | pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) %void { | 1151 | pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) !void { |
| 1067 | const path_buf = try allocator.alloc(u8, dir_path.len + 1); | 1152 | const path_buf = try allocator.alloc(u8, dir_path.len + 1); |
| 1068 | defer allocator.free(path_buf); | 1153 | defer allocator.free(path_buf); |
| 1069 | 1154 | ||
| ... | @@ -1087,7 +1172,7 @@ pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) %void { | ... | @@ -1087,7 +1172,7 @@ pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) %void { |
| 1087 | } | 1172 | } |
| 1088 | 1173 | ||
| 1089 | /// Read value of a symbolic link. | 1174 | /// Read value of a symbolic link. |
| 1090 | pub fn readLink(allocator: &Allocator, pathname: []const u8) %[]u8 { | 1175 | pub fn readLink(allocator: &Allocator, pathname: []const u8) ![]u8 { |
| 1091 | const path_buf = try allocator.alloc(u8, pathname.len + 1); | 1176 | const path_buf = try allocator.alloc(u8, pathname.len + 1); |
| 1092 | defer allocator.free(path_buf); | 1177 | defer allocator.free(path_buf); |
| 1093 | 1178 | ||
| ... | @@ -1164,11 +1249,7 @@ test "os.sleep" { | ... | @@ -1164,11 +1249,7 @@ test "os.sleep" { |
| 1164 | sleep(0, 1); | 1249 | sleep(0, 1); |
| 1165 | } | 1250 | } |
| 1166 | 1251 | ||
| 1167 | error ResourceLimitReached; | 1252 | pub fn posix_setuid(uid: u32) !void { |
| 1168 | error InvalidUserId; | ||
| 1169 | error PermissionDenied; | ||
| 1170 | |||
| 1171 | pub fn posix_setuid(uid: u32) %void { | ||
| 1172 | const err = posix.getErrno(posix.setuid(uid)); | 1253 | const err = posix.getErrno(posix.setuid(uid)); |
| 1173 | if (err == 0) return; | 1254 | if (err == 0) return; |
| 1174 | return switch (err) { | 1255 | return switch (err) { |
| ... | @@ -1179,7 +1260,7 @@ pub fn posix_setuid(uid: u32) %void { | ... | @@ -1179,7 +1260,7 @@ pub fn posix_setuid(uid: u32) %void { |
| 1179 | }; | 1260 | }; |
| 1180 | } | 1261 | } |
| 1181 | 1262 | ||
| 1182 | pub fn posix_setreuid(ruid: u32, euid: u32) %void { | 1263 | pub fn posix_setreuid(ruid: u32, euid: u32) !void { |
| 1183 | const err = posix.getErrno(posix.setreuid(ruid, euid)); | 1264 | const err = posix.getErrno(posix.setreuid(ruid, euid)); |
| 1184 | if (err == 0) return; | 1265 | if (err == 0) return; |
| 1185 | return switch (err) { | 1266 | return switch (err) { |
| ... | @@ -1190,7 +1271,7 @@ pub fn posix_setreuid(ruid: u32, euid: u32) %void { | ... | @@ -1190,7 +1271,7 @@ pub fn posix_setreuid(ruid: u32, euid: u32) %void { |
| 1190 | }; | 1271 | }; |
| 1191 | } | 1272 | } |
| 1192 | 1273 | ||
| 1193 | pub fn posix_setgid(gid: u32) %void { | 1274 | pub fn posix_setgid(gid: u32) !void { |
| 1194 | const err = posix.getErrno(posix.setgid(gid)); | 1275 | const err = posix.getErrno(posix.setgid(gid)); |
| 1195 | if (err == 0) return; | 1276 | if (err == 0) return; |
| 1196 | return switch (err) { | 1277 | return switch (err) { |
| ... | @@ -1201,7 +1282,7 @@ pub fn posix_setgid(gid: u32) %void { | ... | @@ -1201,7 +1282,7 @@ pub fn posix_setgid(gid: u32) %void { |
| 1201 | }; | 1282 | }; |
| 1202 | } | 1283 | } |
| 1203 | 1284 | ||
| 1204 | pub fn posix_setregid(rgid: u32, egid: u32) %void { | 1285 | pub fn posix_setregid(rgid: u32, egid: u32) !void { |
| 1205 | const err = posix.getErrno(posix.setregid(rgid, egid)); | 1286 | const err = posix.getErrno(posix.setregid(rgid, egid)); |
| 1206 | if (err == 0) return; | 1287 | if (err == 0) return; |
| 1207 | return switch (err) { | 1288 | return switch (err) { |
| ... | @@ -1212,8 +1293,12 @@ pub fn posix_setregid(rgid: u32, egid: u32) %void { | ... | @@ -1212,8 +1293,12 @@ pub fn posix_setregid(rgid: u32, egid: u32) %void { |
| 1212 | }; | 1293 | }; |
| 1213 | } | 1294 | } |
| 1214 | 1295 | ||
| 1215 | error NoStdHandles; | 1296 | pub const WindowsGetStdHandleErrs = error { |
| 1216 | pub fn windowsGetStdHandle(handle_id: windows.DWORD) %windows.HANDLE { | 1297 | NoStdHandles, |
| 1298 | Unexpected, | ||
| 1299 | }; | ||
| 1300 | |||
| 1301 | pub fn windowsGetStdHandle(handle_id: windows.DWORD) WindowsGetStdHandleErrs!windows.HANDLE { | ||
| 1217 | if (windows.GetStdHandle(handle_id)) |handle| { | 1302 | if (windows.GetStdHandle(handle_id)) |handle| { |
| 1218 | if (handle == windows.INVALID_HANDLE_VALUE) { | 1303 | if (handle == windows.INVALID_HANDLE_VALUE) { |
| 1219 | const err = windows.GetLastError(); | 1304 | const err = windows.GetLastError(); |
| ... | @@ -1267,6 +1352,8 @@ pub const ArgIteratorWindows = struct { | ... | @@ -1267,6 +1352,8 @@ pub const ArgIteratorWindows = struct { |
| 1267 | quote_count: usize, | 1352 | quote_count: usize, |
| 1268 | seen_quote_count: usize, | 1353 | seen_quote_count: usize, |
| 1269 | 1354 | ||
| 1355 | pub const NextError = error{OutOfMemory}; | ||
| 1356 | |||
| 1270 | pub fn init() ArgIteratorWindows { | 1357 | pub fn init() ArgIteratorWindows { |
| 1271 | return initWithCmdLine(windows.GetCommandLineA()); | 1358 | return initWithCmdLine(windows.GetCommandLineA()); |
| 1272 | } | 1359 | } |
| ... | @@ -1282,7 +1369,7 @@ pub const ArgIteratorWindows = struct { | ... | @@ -1282,7 +1369,7 @@ pub const ArgIteratorWindows = struct { |
| 1282 | } | 1369 | } |
| 1283 | 1370 | ||
| 1284 | /// You must free the returned memory when done. | 1371 | /// You must free the returned memory when done. |
| 1285 | pub fn next(self: &ArgIteratorWindows, allocator: &Allocator) ?%[]u8 { | 1372 | pub fn next(self: &ArgIteratorWindows, allocator: &Allocator) ?(NextError![]u8) { |
| 1286 | // march forward over whitespace | 1373 | // march forward over whitespace |
| 1287 | while (true) : (self.index += 1) { | 1374 | while (true) : (self.index += 1) { |
| 1288 | const byte = self.cmd_line[self.index]; | 1375 | const byte = self.cmd_line[self.index]; |
| ... | @@ -1335,7 +1422,7 @@ pub const ArgIteratorWindows = struct { | ... | @@ -1335,7 +1422,7 @@ pub const ArgIteratorWindows = struct { |
| 1335 | } | 1422 | } |
| 1336 | } | 1423 | } |
| 1337 | 1424 | ||
| 1338 | fn internalNext(self: &ArgIteratorWindows, allocator: &Allocator) %[]u8 { | 1425 | fn internalNext(self: &ArgIteratorWindows, allocator: &Allocator) NextError![]u8 { |
| 1339 | var buf = try Buffer.initSize(allocator, 0); | 1426 | var buf = try Buffer.initSize(allocator, 0); |
| 1340 | defer buf.deinit(); | 1427 | defer buf.deinit(); |
| 1341 | 1428 | ||
| ... | @@ -1379,7 +1466,7 @@ pub const ArgIteratorWindows = struct { | ... | @@ -1379,7 +1466,7 @@ pub const ArgIteratorWindows = struct { |
| 1379 | } | 1466 | } |
| 1380 | } | 1467 | } |
| 1381 | 1468 | ||
| 1382 | fn emitBackslashes(self: &ArgIteratorWindows, buf: &Buffer, emit_count: usize) %void { | 1469 | fn emitBackslashes(self: &ArgIteratorWindows, buf: &Buffer, emit_count: usize) !void { |
| 1383 | var i: usize = 0; | 1470 | var i: usize = 0; |
| 1384 | while (i < emit_count) : (i += 1) { | 1471 | while (i < emit_count) : (i += 1) { |
| 1385 | try buf.appendByte('\\'); | 1472 | try buf.appendByte('\\'); |
| ... | @@ -1409,16 +1496,20 @@ pub const ArgIteratorWindows = struct { | ... | @@ -1409,16 +1496,20 @@ pub const ArgIteratorWindows = struct { |
| 1409 | }; | 1496 | }; |
| 1410 | 1497 | ||
| 1411 | pub const ArgIterator = struct { | 1498 | pub 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, | ||
| 1413 | 1502 | ||
| 1414 | pub fn init() ArgIterator { | 1503 | pub fn init() ArgIterator { |
| 1415 | return ArgIterator { | 1504 | return ArgIterator { |
| 1416 | .inner = if (builtin.os == Os.windows) ArgIteratorWindows.init() else ArgIteratorPosix.init(), | 1505 | .inner = InnerType.init(), |
| 1417 | }; | 1506 | }; |
| 1418 | } | 1507 | } |
| 1508 | |||
| 1509 | pub const NextError = ArgIteratorWindows.NextError; | ||
| 1419 | 1510 | ||
| 1420 | /// You must free the returned memory when done. | 1511 | /// You must free the returned memory when done. |
| 1421 | pub fn next(self: &ArgIterator, allocator: &Allocator) ?%[]u8 { | 1512 | pub fn next(self: &ArgIterator, allocator: &Allocator) ?(NextError![]u8) { |
| 1422 | if (builtin.os == Os.windows) { | 1513 | if (builtin.os == Os.windows) { |
| 1423 | return self.inner.next(allocator); | 1514 | return self.inner.next(allocator); |
| 1424 | } else { | 1515 | } else { |
| ... | @@ -1443,7 +1534,7 @@ pub fn args() ArgIterator { | ... | @@ -1443,7 +1534,7 @@ pub fn args() ArgIterator { |
| 1443 | } | 1534 | } |
| 1444 | 1535 | ||
| 1445 | /// Caller must call freeArgs on result. | 1536 | /// Caller must call freeArgs on result. |
| 1446 | pub fn argsAlloc(allocator: &mem.Allocator) %[]const []u8 { | 1537 | pub fn argsAlloc(allocator: &mem.Allocator) ![]const []u8 { |
| 1447 | // TODO refactor to only make 1 allocation. | 1538 | // TODO refactor to only make 1 allocation. |
| 1448 | var it = args(); | 1539 | var it = args(); |
| 1449 | var contents = try Buffer.initSize(allocator, 0); | 1540 | var contents = try Buffer.initSize(allocator, 0); |
| ... | @@ -1525,14 +1616,12 @@ test "std.os" { | ... | @@ -1525,14 +1616,12 @@ test "std.os" { |
| 1525 | } | 1616 | } |
| 1526 | 1617 | ||
| 1527 | 1618 | ||
| 1528 | error Unexpected; | ||
| 1529 | |||
| 1530 | // TODO make this a build variable that you can set | 1619 | // TODO make this a build variable that you can set |
| 1531 | const unexpected_error_tracing = false; | 1620 | const unexpected_error_tracing = false; |
| 1532 | 1621 | ||
| 1533 | /// Call this when you made a syscall or something that sets errno | 1622 | /// Call this when you made a syscall or something that sets errno |
| 1534 | /// and you get an unexpected error. | 1623 | /// and you get an unexpected error. |
| 1535 | pub fn unexpectedErrorPosix(errno: usize) error { | 1624 | pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) { |
| 1536 | if (unexpected_error_tracing) { | 1625 | if (unexpected_error_tracing) { |
| 1537 | debug.warn("unexpected errno: {}\n", errno); | 1626 | debug.warn("unexpected errno: {}\n", errno); |
| 1538 | debug.dumpStackTrace(); | 1627 | debug.dumpStackTrace(); |
| ... | @@ -1542,7 +1631,7 @@ pub fn unexpectedErrorPosix(errno: usize) error { | ... | @@ -1542,7 +1631,7 @@ pub fn unexpectedErrorPosix(errno: usize) error { |
| 1542 | 1631 | ||
| 1543 | /// Call this when you made a windows DLL call or something that does SetLastError | 1632 | /// Call this when you made a windows DLL call or something that does SetLastError |
| 1544 | /// and you get an unexpected error. | 1633 | /// and you get an unexpected error. |
| 1545 | pub fn unexpectedErrorWindows(err: windows.DWORD) error { | 1634 | pub fn unexpectedErrorWindows(err: windows.DWORD) (error{Unexpected}) { |
| 1546 | if (unexpected_error_tracing) { | 1635 | if (unexpected_error_tracing) { |
| 1547 | debug.warn("unexpected GetLastError(): {}\n", err); | 1636 | debug.warn("unexpected GetLastError(): {}\n", err); |
| 1548 | debug.dumpStackTrace(); | 1637 | debug.dumpStackTrace(); |
| ... | @@ -1550,7 +1639,7 @@ pub fn unexpectedErrorWindows(err: windows.DWORD) error { | ... | @@ -1550,7 +1639,7 @@ pub fn unexpectedErrorWindows(err: windows.DWORD) error { |
| 1550 | return error.Unexpected; | 1639 | return error.Unexpected; |
| 1551 | } | 1640 | } |
| 1552 | 1641 | ||
| 1553 | pub fn openSelfExe() %io.File { | 1642 | pub fn openSelfExe() !io.File { |
| 1554 | switch (builtin.os) { | 1643 | switch (builtin.os) { |
| 1555 | Os.linux => { | 1644 | Os.linux => { |
| 1556 | return io.File.openRead("/proc/self/exe", null); | 1645 | return io.File.openRead("/proc/self/exe", null); |
| ... | @@ -1578,7 +1667,7 @@ test "openSelfExe" { | ... | @@ -1578,7 +1667,7 @@ test "openSelfExe" { |
| 1578 | /// This function may return an error if the current executable | 1667 | /// This function may return an error if the current executable |
| 1579 | /// was deleted after spawning. | 1668 | /// was deleted after spawning. |
| 1580 | /// Caller owns returned memory. | 1669 | /// Caller owns returned memory. |
| 1581 | pub fn selfExePath(allocator: &mem.Allocator) %[]u8 { | 1670 | pub fn selfExePath(allocator: &mem.Allocator) ![]u8 { |
| 1582 | switch (builtin.os) { | 1671 | switch (builtin.os) { |
| 1583 | Os.linux => { | 1672 | Os.linux => { |
| 1584 | // If the currently executing binary has been deleted, | 1673 | // If the currently executing binary has been deleted, |
| ... | @@ -1621,7 +1710,7 @@ pub fn selfExePath(allocator: &mem.Allocator) %[]u8 { | ... | @@ -1621,7 +1710,7 @@ pub fn selfExePath(allocator: &mem.Allocator) %[]u8 { |
| 1621 | 1710 | ||
| 1622 | /// Get the directory path that contains the current executable. | 1711 | /// Get the directory path that contains the current executable. |
| 1623 | /// Caller owns returned memory. | 1712 | /// Caller owns returned memory. |
| 1624 | pub fn selfExeDirPath(allocator: &mem.Allocator) %[]u8 { | 1713 | pub fn selfExeDirPath(allocator: &mem.Allocator) ![]u8 { |
| 1625 | switch (builtin.os) { | 1714 | switch (builtin.os) { |
| 1626 | Os.linux => { | 1715 | Os.linux => { |
| 1627 | // If the currently executing binary has been deleted, | 1716 | // If the currently executing binary has been deleted, |
std/os/linux/index.zig+1-1| ... | @@ -720,7 +720,7 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: | ... | @@ -720,7 +720,7 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: |
| 720 | // error SystemResources; | 720 | // error SystemResources; |
| 721 | // error Io; | 721 | // error Io; |
| 722 | // | 722 | // |
| 723 | // pub fn if_nametoindex(name: []u8) %u32 { | 723 | // pub fn if_nametoindex(name: []u8) !u32 { |
| 724 | // var ifr: ifreq = undefined; | 724 | // var ifr: ifreq = undefined; |
| 725 | // | 725 | // |
| 726 | // if (name.len >= ifr.ifr_name.len) { | 726 | // if (name.len >= ifr.ifr_name.len) { |
std/os/path.zig+11-18| ... | @@ -32,7 +32,7 @@ pub fn isSep(byte: u8) bool { | ... | @@ -32,7 +32,7 @@ pub fn isSep(byte: u8) bool { |
| 32 | 32 | ||
| 33 | /// Naively combines a series of paths with the native path seperator. | 33 | /// Naively combines a series of paths with the native path seperator. |
| 34 | /// Allocates memory for the result, which must be freed by the caller. | 34 | /// Allocates memory for the result, which must be freed by the caller. |
| 35 | pub fn join(allocator: &Allocator, paths: ...) %[]u8 { | 35 | pub fn join(allocator: &Allocator, paths: ...) ![]u8 { |
| 36 | if (is_windows) { | 36 | if (is_windows) { |
| 37 | return joinWindows(allocator, paths); | 37 | return joinWindows(allocator, paths); |
| 38 | } else { | 38 | } else { |
| ... | @@ -40,11 +40,11 @@ pub fn join(allocator: &Allocator, paths: ...) %[]u8 { | ... | @@ -40,11 +40,11 @@ pub fn join(allocator: &Allocator, paths: ...) %[]u8 { |
| 40 | } | 40 | } |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | pub fn joinWindows(allocator: &Allocator, paths: ...) %[]u8 { | 43 | pub fn joinWindows(allocator: &Allocator, paths: ...) ![]u8 { |
| 44 | return mem.join(allocator, sep_windows, paths); | 44 | return mem.join(allocator, sep_windows, paths); |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | pub fn joinPosix(allocator: &Allocator, paths: ...) %[]u8 { | 47 | pub fn joinPosix(allocator: &Allocator, paths: ...) ![]u8 { |
| 48 | return mem.join(allocator, sep_posix, paths); | 48 | return mem.join(allocator, sep_posix, paths); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| ... | @@ -313,7 +313,7 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool { | ... | @@ -313,7 +313,7 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool { |
| 313 | } | 313 | } |
| 314 | 314 | ||
| 315 | /// Converts the command line arguments into a slice and calls `resolveSlice`. | 315 | /// Converts the command line arguments into a slice and calls `resolveSlice`. |
| 316 | pub fn resolve(allocator: &Allocator, args: ...) %[]u8 { | 316 | pub fn resolve(allocator: &Allocator, args: ...) ![]u8 { |
| 317 | var paths: [args.len][]const u8 = undefined; | 317 | var paths: [args.len][]const u8 = undefined; |
| 318 | comptime var arg_i = 0; | 318 | comptime var arg_i = 0; |
| 319 | inline while (arg_i < args.len) : (arg_i += 1) { | 319 | inline while (arg_i < args.len) : (arg_i += 1) { |
| ... | @@ -323,7 +323,7 @@ pub fn resolve(allocator: &Allocator, args: ...) %[]u8 { | ... | @@ -323,7 +323,7 @@ pub fn resolve(allocator: &Allocator, args: ...) %[]u8 { |
| 323 | } | 323 | } |
| 324 | 324 | ||
| 325 | /// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`. | 325 | /// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`. |
| 326 | pub fn resolveSlice(allocator: &Allocator, paths: []const []const u8) %[]u8 { | 326 | pub fn resolveSlice(allocator: &Allocator, paths: []const []const u8) ![]u8 { |
| 327 | if (is_windows) { | 327 | if (is_windows) { |
| 328 | return resolveWindows(allocator, paths); | 328 | return resolveWindows(allocator, paths); |
| 329 | } else { | 329 | } else { |
| ... | @@ -337,7 +337,7 @@ pub fn resolveSlice(allocator: &Allocator, paths: []const []const u8) %[]u8 { | ... | @@ -337,7 +337,7 @@ pub fn resolveSlice(allocator: &Allocator, paths: []const []const u8) %[]u8 { |
| 337 | /// If all paths are relative it uses the current working directory as a starting point. | 337 | /// If all paths are relative it uses the current working directory as a starting point. |
| 338 | /// Each drive has its own current working directory. | 338 | /// Each drive has its own current working directory. |
| 339 | /// Path separators are canonicalized to '\\' and drives are canonicalized to capital letters. | 339 | /// Path separators are canonicalized to '\\' and drives are canonicalized to capital letters. |
| 340 | pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) %[]u8 { | 340 | pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) ![]u8 { |
| 341 | if (paths.len == 0) { | 341 | if (paths.len == 0) { |
| 342 | assert(is_windows); // resolveWindows called on non windows can't use getCwd | 342 | assert(is_windows); // resolveWindows called on non windows can't use getCwd |
| 343 | return os.getCwd(allocator); | 343 | return os.getCwd(allocator); |
| ... | @@ -520,7 +520,7 @@ pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) %[]u8 { | ... | @@ -520,7 +520,7 @@ pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) %[]u8 { |
| 520 | /// It resolves "." and "..". | 520 | /// It resolves "." and "..". |
| 521 | /// The result does not have a trailing path separator. | 521 | /// The result does not have a trailing path separator. |
| 522 | /// If all paths are relative it uses the current working directory as a starting point. | 522 | /// If all paths are relative it uses the current working directory as a starting point. |
| 523 | pub fn resolvePosix(allocator: &Allocator, paths: []const []const u8) %[]u8 { | 523 | pub fn resolvePosix(allocator: &Allocator, paths: []const []const u8) ![]u8 { |
| 524 | if (paths.len == 0) { | 524 | if (paths.len == 0) { |
| 525 | assert(!is_windows); // resolvePosix called on windows can't use getCwd | 525 | assert(!is_windows); // resolvePosix called on windows can't use getCwd |
| 526 | return os.getCwd(allocator); | 526 | return os.getCwd(allocator); |
| ... | @@ -890,7 +890,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) void { | ... | @@ -890,7 +890,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) void { |
| 890 | /// resolve to the same path (after calling `resolve` on each), a zero-length | 890 | /// resolve to the same path (after calling `resolve` on each), a zero-length |
| 891 | /// string is returned. | 891 | /// string is returned. |
| 892 | /// On Windows this canonicalizes the drive to a capital letter and paths to `\\`. | 892 | /// On Windows this canonicalizes the drive to a capital letter and paths to `\\`. |
| 893 | pub fn relative(allocator: &Allocator, from: []const u8, to: []const u8) %[]u8 { | 893 | pub fn relative(allocator: &Allocator, from: []const u8, to: []const u8) ![]u8 { |
| 894 | if (is_windows) { | 894 | if (is_windows) { |
| 895 | return relativeWindows(allocator, from, to); | 895 | return relativeWindows(allocator, from, to); |
| 896 | } else { | 896 | } else { |
| ... | @@ -898,7 +898,7 @@ pub fn relative(allocator: &Allocator, from: []const u8, to: []const u8) %[]u8 { | ... | @@ -898,7 +898,7 @@ pub fn relative(allocator: &Allocator, from: []const u8, to: []const u8) %[]u8 { |
| 898 | } | 898 | } |
| 899 | } | 899 | } |
| 900 | 900 | ||
| 901 | pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8) %[]u8 { | 901 | pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8) ![]u8 { |
| 902 | const resolved_from = try resolveWindows(allocator, [][]const u8{from}); | 902 | const resolved_from = try resolveWindows(allocator, [][]const u8{from}); |
| 903 | defer allocator.free(resolved_from); | 903 | defer allocator.free(resolved_from); |
| 904 | 904 | ||
| ... | @@ -971,7 +971,7 @@ pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8) | ... | @@ -971,7 +971,7 @@ pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8) |
| 971 | return []u8{}; | 971 | return []u8{}; |
| 972 | } | 972 | } |
| 973 | 973 | ||
| 974 | pub fn relativePosix(allocator: &Allocator, from: []const u8, to: []const u8) %[]u8 { | 974 | pub fn relativePosix(allocator: &Allocator, from: []const u8, to: []const u8) ![]u8 { |
| 975 | const resolved_from = try resolvePosix(allocator, [][]const u8{from}); | 975 | const resolved_from = try resolvePosix(allocator, [][]const u8{from}); |
| 976 | defer allocator.free(resolved_from); | 976 | defer allocator.free(resolved_from); |
| 977 | 977 | ||
| ... | @@ -1066,18 +1066,11 @@ fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []cons | ... | @@ -1066,18 +1066,11 @@ fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []cons |
| 1066 | assert(mem.eql(u8, result, expected_output)); | 1066 | assert(mem.eql(u8, result, expected_output)); |
| 1067 | } | 1067 | } |
| 1068 | 1068 | ||
| 1069 | error AccessDenied; | ||
| 1070 | error FileNotFound; | ||
| 1071 | error NotSupported; | ||
| 1072 | error NotDir; | ||
| 1073 | error NameTooLong; | ||
| 1074 | error SymLinkLoop; | ||
| 1075 | error InputOutput; | ||
| 1076 | /// Return the canonicalized absolute pathname. | 1069 | /// Return the canonicalized absolute pathname. |
| 1077 | /// Expands all symbolic links and resolves references to `.`, `..`, and | 1070 | /// Expands all symbolic links and resolves references to `.`, `..`, and |
| 1078 | /// extra `/` characters in ::pathname. | 1071 | /// extra `/` characters in ::pathname. |
| 1079 | /// Caller must deallocate result. | 1072 | /// Caller must deallocate result. |
| 1080 | pub fn real(allocator: &Allocator, pathname: []const u8) %[]u8 { | 1073 | pub fn real(allocator: &Allocator, pathname: []const u8) ![]u8 { |
| 1081 | switch (builtin.os) { | 1074 | switch (builtin.os) { |
| 1082 | Os.windows => { | 1075 | Os.windows => { |
| 1083 | const pathname_buf = try allocator.alloc(u8, pathname.len + 1); | 1076 | const pathname_buf = try allocator.alloc(u8, pathname.len + 1); |
std/os/windows/util.zig+42-26| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const std = @import("../../index.zig"); | 1 | const std = @import("../../index.zig"); |
| 2 | const builtin = @import("builtin"); | ||
| 2 | const os = std.os; | 3 | const os = std.os; |
| 3 | const windows = std.os.windows; | 4 | const windows = std.os.windows; |
| 4 | const assert = std.debug.assert; | 5 | const assert = std.debug.assert; |
| ... | @@ -6,11 +7,13 @@ const mem = std.mem; | ... | @@ -6,11 +7,13 @@ const mem = std.mem; |
| 6 | const BufMap = std.BufMap; | 7 | const BufMap = std.BufMap; |
| 7 | const cstr = std.cstr; | 8 | const cstr = std.cstr; |
| 8 | 9 | ||
| 9 | error WaitAbandoned; | 10 | pub const WaitError = error { |
| 10 | error WaitTimeOut; | 11 | WaitAbandoned, |
| 11 | error Unexpected; | 12 | WaitTimeOut, |
| 13 | Unexpected, | ||
| 14 | }; | ||
| 12 | 15 | ||
| 13 | pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) %void { | 16 | pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) WaitError!void { |
| 14 | const result = windows.WaitForSingleObject(handle, milliseconds); | 17 | const result = windows.WaitForSingleObject(handle, milliseconds); |
| 15 | return switch (result) { | 18 | return switch (result) { |
| 16 | windows.WAIT_ABANDONED => error.WaitAbandoned, | 19 | windows.WAIT_ABANDONED => error.WaitAbandoned, |
| ... | @@ -30,21 +33,24 @@ pub fn windowsClose(handle: windows.HANDLE) void { | ... | @@ -30,21 +33,24 @@ pub fn windowsClose(handle: windows.HANDLE) void { |
| 30 | assert(windows.CloseHandle(handle) != 0); | 33 | assert(windows.CloseHandle(handle) != 0); |
| 31 | } | 34 | } |
| 32 | 35 | ||
| 33 | error SystemResources; | 36 | pub const WriteError = error { |
| 34 | error OperationAborted; | 37 | SystemResources, |
| 35 | error IoPending; | 38 | OperationAborted, |
| 36 | error BrokenPipe; | 39 | IoPending, |
| 40 | BrokenPipe, | ||
| 41 | Unexpected, | ||
| 42 | }; | ||
| 37 | 43 | ||
| 38 | pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) %void { | 44 | pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) WriteError!void { |
| 39 | if (windows.WriteFile(handle, @ptrCast(&const c_void, bytes.ptr), u32(bytes.len), null, null) == 0) { | 45 | if (windows.WriteFile(handle, @ptrCast(&const c_void, bytes.ptr), u32(bytes.len), null, null) == 0) { |
| 40 | const err = windows.GetLastError(); | 46 | const err = windows.GetLastError(); |
| 41 | return switch (err) { | 47 | return switch (err) { |
| 42 | windows.ERROR.INVALID_USER_BUFFER => error.SystemResources, | 48 | windows.ERROR.INVALID_USER_BUFFER => WriteError.SystemResources, |
| 43 | windows.ERROR.NOT_ENOUGH_MEMORY => error.SystemResources, | 49 | windows.ERROR.NOT_ENOUGH_MEMORY => WriteError.SystemResources, |
| 44 | windows.ERROR.OPERATION_ABORTED => error.OperationAborted, | 50 | windows.ERROR.OPERATION_ABORTED => WriteError.OperationAborted, |
| 45 | windows.ERROR.NOT_ENOUGH_QUOTA => error.SystemResources, | 51 | windows.ERROR.NOT_ENOUGH_QUOTA => WriteError.SystemResources, |
| 46 | windows.ERROR.IO_PENDING => error.IoPending, | 52 | windows.ERROR.IO_PENDING => WriteError.IoPending, |
| 47 | windows.ERROR.BROKEN_PIPE => error.BrokenPipe, | 53 | windows.ERROR.BROKEN_PIPE => WriteError.BrokenPipe, |
| 48 | else => os.unexpectedErrorWindows(err), | 54 | else => os.unexpectedErrorWindows(err), |
| 49 | }; | 55 | }; |
| 50 | } | 56 | } |
| ... | @@ -75,15 +81,24 @@ pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool { | ... | @@ -75,15 +81,24 @@ pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool { |
| 75 | mem.indexOf(u16, name_wide, []u16{'-','p','t','y'}) != null; | 81 | mem.indexOf(u16, name_wide, []u16{'-','p','t','y'}) != null; |
| 76 | } | 82 | } |
| 77 | 83 | ||
| 78 | error SharingViolation; | 84 | pub const OpenError = error { |
| 79 | error PipeBusy; | 85 | SharingViolation, |
| 86 | PathAlreadyExists, | ||
| 87 | FileNotFound, | ||
| 88 | AccessDenied, | ||
| 89 | PipeBusy, | ||
| 90 | Unexpected, | ||
| 91 | OutOfMemory, | ||
| 92 | NameTooLong, | ||
| 93 | }; | ||
| 80 | 94 | ||
| 81 | /// `file_path` may need to be copied in memory to add a null terminating byte. In this case | 95 | /// `file_path` may need to be copied in memory to add a null terminating byte. In this case |
| 82 | /// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed | 96 | /// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed |
| 83 | /// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned. | 97 | /// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned. |
| 84 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. | 98 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. |
| 85 | pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_mode: windows.DWORD, | 99 | pub 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 | ||
| 87 | { | 102 | { |
| 88 | var stack_buf: [os.max_noalloc_path_len]u8 = undefined; | 103 | var stack_buf: [os.max_noalloc_path_len]u8 = undefined; |
| 89 | var path0: []u8 = undefined; | 104 | var path0: []u8 = undefined; |
| ... | @@ -107,11 +122,11 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m | ... | @@ -107,11 +122,11 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m |
| 107 | if (result == windows.INVALID_HANDLE_VALUE) { | 122 | if (result == windows.INVALID_HANDLE_VALUE) { |
| 108 | const err = windows.GetLastError(); | 123 | const err = windows.GetLastError(); |
| 109 | return switch (err) { | 124 | return switch (err) { |
| 110 | windows.ERROR.SHARING_VIOLATION => error.SharingViolation, | 125 | windows.ERROR.SHARING_VIOLATION => OpenError.SharingViolation, |
| 111 | windows.ERROR.ALREADY_EXISTS, windows.ERROR.FILE_EXISTS => error.PathAlreadyExists, | 126 | windows.ERROR.ALREADY_EXISTS, windows.ERROR.FILE_EXISTS => OpenError.PathAlreadyExists, |
| 112 | windows.ERROR.FILE_NOT_FOUND => error.FileNotFound, | 127 | windows.ERROR.FILE_NOT_FOUND => OpenError.FileNotFound, |
| 113 | windows.ERROR.ACCESS_DENIED => error.AccessDenied, | 128 | windows.ERROR.ACCESS_DENIED => OpenError.AccessDenied, |
| 114 | windows.ERROR.PIPE_BUSY => error.PipeBusy, | 129 | windows.ERROR.PIPE_BUSY => OpenError.PipeBusy, |
| 115 | else => os.unexpectedErrorWindows(err), | 130 | else => os.unexpectedErrorWindows(err), |
| 116 | }; | 131 | }; |
| 117 | } | 132 | } |
| ... | @@ -120,7 +135,7 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m | ... | @@ -120,7 +135,7 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m |
| 120 | } | 135 | } |
| 121 | 136 | ||
| 122 | /// Caller must free result. | 137 | /// Caller must free result. |
| 123 | pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) %[]u8 { | 138 | pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) ![]u8 { |
| 124 | // count bytes needed | 139 | // count bytes needed |
| 125 | const bytes_needed = x: { | 140 | const bytes_needed = x: { |
| 126 | var bytes_needed: usize = 1; // 1 for the final null byte | 141 | var bytes_needed: usize = 1; // 1 for the final null byte |
| ... | @@ -151,8 +166,7 @@ pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) | ... | @@ -151,8 +166,7 @@ pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) |
| 151 | return result; | 166 | return result; |
| 152 | } | 167 | } |
| 153 | 168 | ||
| 154 | error DllNotFound; | 169 | pub fn windowsLoadDll(allocator: &mem.Allocator, dll_path: []const u8) !windows.HMODULE { |
| 155 | pub fn windowsLoadDll(allocator: &mem.Allocator, dll_path: []const u8) %windows.HMODULE { | ||
| 156 | const padded_buff = try cstr.addNullByte(allocator, dll_path); | 170 | const padded_buff = try cstr.addNullByte(allocator, dll_path); |
| 157 | defer allocator.free(padded_buff); | 171 | defer allocator.free(padded_buff); |
| 158 | return windows.LoadLibraryA(padded_buff.ptr) ?? error.DllNotFound; | 172 | return windows.LoadLibraryA(padded_buff.ptr) ?? error.DllNotFound; |
| ... | @@ -164,6 +178,8 @@ pub fn windowsUnloadDll(hModule: windows.HMODULE) void { | ... | @@ -164,6 +178,8 @@ pub fn windowsUnloadDll(hModule: windows.HMODULE) void { |
| 164 | 178 | ||
| 165 | 179 | ||
| 166 | test "InvalidDll" { | 180 | test "InvalidDll" { |
| 181 | if (builtin.os != builtin.Os.windows) return; | ||
| 182 | |||
| 167 | const DllName = "asdf.dll"; | 183 | const DllName = "asdf.dll"; |
| 168 | const allocator = std.debug.global_allocator; | 184 | const allocator = std.debug.global_allocator; |
| 169 | const handle = os.windowsLoadDll(allocator, DllName) catch |err| { | 185 | const handle = os.windowsLoadDll(allocator, DllName) catch |err| { |
std/special/bootstrap.zig+2-2| ... | @@ -77,7 +77,7 @@ fn callMain() u8 { | ... | @@ -77,7 +77,7 @@ fn callMain() u8 { |
| 77 | }, | 77 | }, |
| 78 | builtin.TypeId.Int => { | 78 | builtin.TypeId.Int => { |
| 79 | if (@typeOf(root.main).ReturnType.bit_count != 8) { | 79 | if (@typeOf(root.main).ReturnType.bit_count != 8) { |
| 80 | @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '%void'"); | 80 | @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"); |
| 81 | } | 81 | } |
| 82 | return root.main(); | 82 | return root.main(); |
| 83 | }, | 83 | }, |
| ... | @@ -91,6 +91,6 @@ fn callMain() u8 { | ... | @@ -91,6 +91,6 @@ fn callMain() u8 { |
| 91 | }; | 91 | }; |
| 92 | return 0; | 92 | return 0; |
| 93 | }, | 93 | }, |
| 94 | else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '%void'"), | 94 | else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"), |
| 95 | } | 95 | } |
| 96 | } | 96 | } |
std/special/build_file_template.zig+1-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | const Builder = @import("std").build.Builder; | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | ||
| 3 | pub fn build(b: &Builder) %void { | 3 | pub fn build(b: &Builder) !void { |
| 4 | const mode = b.standardReleaseOptions(); | 4 | const mode = b.standardReleaseOptions(); |
| 5 | const exe = b.addExecutable("YOUR_NAME_HERE", "src/main.zig"); | 5 | const exe = b.addExecutable("YOUR_NAME_HERE", "src/main.zig"); |
| 6 | exe.setBuildMode(mode); | 6 | exe.setBuildMode(mode); |
std/special/build_runner.zig+19-10| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const root = @import("@build"); | 1 | const root = @import("@build"); |
| 2 | const std = @import("std"); | 2 | const std = @import("std"); |
| 3 | const builtin = @import("builtin"); | ||
| 3 | const io = std.io; | 4 | const io = std.io; |
| 4 | const fmt = std.fmt; | 5 | const fmt = std.fmt; |
| 5 | const os = std.os; | 6 | const os = std.os; |
| ... | @@ -8,9 +9,7 @@ const mem = std.mem; | ... | @@ -8,9 +9,7 @@ const mem = std.mem; |
| 8 | const ArrayList = std.ArrayList; | 9 | const ArrayList = std.ArrayList; |
| 9 | const warn = std.debug.warn; | 10 | const warn = std.debug.warn; |
| 10 | 11 | ||
| 11 | error InvalidArgs; | 12 | pub fn main() !void { |
| 12 | |||
| 13 | pub fn main() %void { | ||
| 14 | var arg_it = os.args(); | 13 | var arg_it = os.args(); |
| 15 | 14 | ||
| 16 | // TODO use a more general purpose allocator here | 15 | // TODO use a more general purpose allocator here |
| ... | @@ -45,14 +44,14 @@ pub fn main() %void { | ... | @@ -45,14 +44,14 @@ pub fn main() %void { |
| 45 | 44 | ||
| 46 | var stderr_file = io.getStdErr(); | 45 | var stderr_file = io.getStdErr(); |
| 47 | var stderr_file_stream: io.FileOutStream = undefined; | 46 | var stderr_file_stream: io.FileOutStream = undefined; |
| 48 | var stderr_stream: %&io.OutStream = if (stderr_file) |*f| x: { | 47 | var stderr_stream = if (stderr_file) |*f| x: { |
| 49 | stderr_file_stream = io.FileOutStream.init(f); | 48 | stderr_file_stream = io.FileOutStream.init(f); |
| 50 | break :x &stderr_file_stream.stream; | 49 | break :x &stderr_file_stream.stream; |
| 51 | } else |err| err; | 50 | } else |err| err; |
| 52 | 51 | ||
| 53 | var stdout_file = io.getStdOut(); | 52 | var stdout_file = io.getStdOut(); |
| 54 | var stdout_file_stream: io.FileOutStream = undefined; | 53 | var stdout_file_stream: io.FileOutStream = undefined; |
| 55 | var stdout_stream: %&io.OutStream = if (stdout_file) |*f| x: { | 54 | var stdout_stream = if (stdout_file) |*f| x: { |
| 56 | stdout_file_stream = io.FileOutStream.init(f); | 55 | stdout_file_stream = io.FileOutStream.init(f); |
| 57 | break :x &stdout_file_stream.stream; | 56 | break :x &stdout_file_stream.stream; |
| 58 | } else |err| err; | 57 | } else |err| err; |
| ... | @@ -112,7 +111,7 @@ pub fn main() %void { | ... | @@ -112,7 +111,7 @@ pub fn main() %void { |
| 112 | } | 111 | } |
| 113 | 112 | ||
| 114 | builder.setInstallPrefix(prefix); | 113 | builder.setInstallPrefix(prefix); |
| 115 | try root.build(&builder); | 114 | try runBuild(&builder); |
| 116 | 115 | ||
| 117 | if (builder.validateUserInputDidItFail()) | 116 | if (builder.validateUserInputDidItFail()) |
| 118 | return usageAndErr(&builder, true, try stderr_stream); | 117 | return usageAndErr(&builder, true, try stderr_stream); |
| ... | @@ -125,11 +124,19 @@ pub fn main() %void { | ... | @@ -125,11 +124,19 @@ pub fn main() %void { |
| 125 | }; | 124 | }; |
| 126 | } | 125 | } |
| 127 | 126 | ||
| 128 | fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) %void { | 127 | fn 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 | |||
| 135 | fn usage(builder: &Builder, already_ran_build: bool, out_stream: var) !void { | ||
| 129 | // run the build script to collect the options | 136 | // run the build script to collect the options |
| 130 | if (!already_ran_build) { | 137 | if (!already_ran_build) { |
| 131 | builder.setInstallPrefix(null); | 138 | builder.setInstallPrefix(null); |
| 132 | try root.build(builder); | 139 | try runBuild(builder); |
| 133 | } | 140 | } |
| 134 | 141 | ||
| 135 | // This usage text has to be synchronized with src/main.cpp | 142 | // This usage text has to be synchronized with src/main.cpp |
| ... | @@ -184,12 +191,14 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) | ... | @@ -184,12 +191,14 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) |
| 184 | ); | 191 | ); |
| 185 | } | 192 | } |
| 186 | 193 | ||
| 187 | fn usageAndErr(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) error { | 194 | fn usageAndErr(builder: &Builder, already_ran_build: bool, out_stream: var) error { |
| 188 | usage(builder, already_ran_build, out_stream) catch {}; | 195 | usage(builder, already_ran_build, out_stream) catch {}; |
| 189 | return error.InvalidArgs; | 196 | return error.InvalidArgs; |
| 190 | } | 197 | } |
| 191 | 198 | ||
| 192 | fn unwrapArg(arg: %[]u8) %[]u8 { | 199 | const UnwrapArgError = error {OutOfMemory}; |
| 200 | |||
| 201 | fn unwrapArg(arg: UnwrapArgError![]u8) UnwrapArgError![]u8 { | ||
| 193 | return arg catch |err| { | 202 | return arg catch |err| { |
| 194 | warn("Unable to parse command line: {}\n", err); | 203 | warn("Unable to parse command line: {}\n", err); |
| 195 | return err; | 204 | return err; |
std/special/test_runner.zig+1-1| ... | @@ -4,7 +4,7 @@ const builtin = @import("builtin"); | ... | @@ -4,7 +4,7 @@ const builtin = @import("builtin"); |
| 4 | const test_fn_list = builtin.__zig_test_fn_slice; | 4 | const test_fn_list = builtin.__zig_test_fn_slice; |
| 5 | const warn = std.debug.warn; | 5 | const warn = std.debug.warn; |
| 6 | 6 | ||
| 7 | pub fn main() %void { | 7 | pub fn main() !void { |
| 8 | for (test_fn_list) |test_fn, i| { | 8 | for (test_fn_list) |test_fn, i| { |
| 9 | warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name); | 9 | warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name); |
| 10 | 10 |
std/unicode.zig+6-14| ... | @@ -1,11 +1,9 @@ | ... | @@ -1,11 +1,9 @@ |
| 1 | const std = @import("./index.zig"); | 1 | const std = @import("./index.zig"); |
| 2 | 2 | ||
| 3 | error Utf8InvalidStartByte; | ||
| 4 | |||
| 5 | /// Given the first byte of a UTF-8 codepoint, | 3 | /// Given the first byte of a UTF-8 codepoint, |
| 6 | /// returns a number 1-4 indicating the total length of the codepoint in bytes. | 4 | /// returns a number 1-4 indicating the total length of the codepoint in bytes. |
| 7 | /// If this byte does not match the form of a UTF-8 start byte, returns Utf8InvalidStartByte. | 5 | /// If this byte does not match the form of a UTF-8 start byte, returns Utf8InvalidStartByte. |
| 8 | pub fn utf8ByteSequenceLength(first_byte: u8) %u3 { | 6 | pub fn utf8ByteSequenceLength(first_byte: u8) !u3 { |
| 9 | if (first_byte < 0b10000000) return u3(1); | 7 | if (first_byte < 0b10000000) return u3(1); |
| 10 | if (first_byte & 0b11100000 == 0b11000000) return u3(2); | 8 | if (first_byte & 0b11100000 == 0b11000000) return u3(2); |
| 11 | if (first_byte & 0b11110000 == 0b11100000) return u3(3); | 9 | if (first_byte & 0b11110000 == 0b11100000) return u3(3); |
| ... | @@ -13,16 +11,11 @@ pub fn utf8ByteSequenceLength(first_byte: u8) %u3 { | ... | @@ -13,16 +11,11 @@ pub fn utf8ByteSequenceLength(first_byte: u8) %u3 { |
| 13 | return error.Utf8InvalidStartByte; | 11 | return error.Utf8InvalidStartByte; |
| 14 | } | 12 | } |
| 15 | 13 | ||
| 16 | error Utf8OverlongEncoding; | ||
| 17 | error Utf8ExpectedContinuation; | ||
| 18 | error Utf8EncodesSurrogateHalf; | ||
| 19 | error Utf8CodepointTooLarge; | ||
| 20 | |||
| 21 | /// Decodes the UTF-8 codepoint encoded in the given slice of bytes. | 14 | /// Decodes the UTF-8 codepoint encoded in the given slice of bytes. |
| 22 | /// bytes.len must be equal to utf8ByteSequenceLength(bytes[0]) catch unreachable. | 15 | /// bytes.len must be equal to utf8ByteSequenceLength(bytes[0]) catch unreachable. |
| 23 | /// If you already know the length at comptime, you can call one of | 16 | /// If you already know the length at comptime, you can call one of |
| 24 | /// utf8Decode2,utf8Decode3,utf8Decode4 directly instead of this function. | 17 | /// utf8Decode2,utf8Decode3,utf8Decode4 directly instead of this function. |
| 25 | pub fn utf8Decode(bytes: []const u8) %u32 { | 18 | pub fn utf8Decode(bytes: []const u8) !u32 { |
| 26 | return switch (bytes.len) { | 19 | return switch (bytes.len) { |
| 27 | 1 => u32(bytes[0]), | 20 | 1 => u32(bytes[0]), |
| 28 | 2 => utf8Decode2(bytes), | 21 | 2 => utf8Decode2(bytes), |
| ... | @@ -31,7 +24,7 @@ pub fn utf8Decode(bytes: []const u8) %u32 { | ... | @@ -31,7 +24,7 @@ pub fn utf8Decode(bytes: []const u8) %u32 { |
| 31 | else => unreachable, | 24 | else => unreachable, |
| 32 | }; | 25 | }; |
| 33 | } | 26 | } |
| 34 | pub fn utf8Decode2(bytes: []const u8) %u32 { | 27 | pub fn utf8Decode2(bytes: []const u8) !u32 { |
| 35 | std.debug.assert(bytes.len == 2); | 28 | std.debug.assert(bytes.len == 2); |
| 36 | std.debug.assert(bytes[0] & 0b11100000 == 0b11000000); | 29 | std.debug.assert(bytes[0] & 0b11100000 == 0b11000000); |
| 37 | var value: u32 = bytes[0] & 0b00011111; | 30 | var value: u32 = bytes[0] & 0b00011111; |
| ... | @@ -44,7 +37,7 @@ pub fn utf8Decode2(bytes: []const u8) %u32 { | ... | @@ -44,7 +37,7 @@ pub fn utf8Decode2(bytes: []const u8) %u32 { |
| 44 | 37 | ||
| 45 | return value; | 38 | return value; |
| 46 | } | 39 | } |
| 47 | pub fn utf8Decode3(bytes: []const u8) %u32 { | 40 | pub fn utf8Decode3(bytes: []const u8) !u32 { |
| 48 | std.debug.assert(bytes.len == 3); | 41 | std.debug.assert(bytes.len == 3); |
| 49 | std.debug.assert(bytes[0] & 0b11110000 == 0b11100000); | 42 | std.debug.assert(bytes[0] & 0b11110000 == 0b11100000); |
| 50 | var value: u32 = bytes[0] & 0b00001111; | 43 | var value: u32 = bytes[0] & 0b00001111; |
| ... | @@ -62,7 +55,7 @@ pub fn utf8Decode3(bytes: []const u8) %u32 { | ... | @@ -62,7 +55,7 @@ pub fn utf8Decode3(bytes: []const u8) %u32 { |
| 62 | 55 | ||
| 63 | return value; | 56 | return value; |
| 64 | } | 57 | } |
| 65 | pub fn utf8Decode4(bytes: []const u8) %u32 { | 58 | pub fn utf8Decode4(bytes: []const u8) !u32 { |
| 66 | std.debug.assert(bytes.len == 4); | 59 | std.debug.assert(bytes.len == 4); |
| 67 | std.debug.assert(bytes[0] & 0b11111000 == 0b11110000); | 60 | std.debug.assert(bytes[0] & 0b11111000 == 0b11110000); |
| 68 | var value: u32 = bytes[0] & 0b00000111; | 61 | var value: u32 = bytes[0] & 0b00000111; |
| ... | @@ -85,7 +78,6 @@ pub fn utf8Decode4(bytes: []const u8) %u32 { | ... | @@ -85,7 +78,6 @@ pub fn utf8Decode4(bytes: []const u8) %u32 { |
| 85 | return value; | 78 | return value; |
| 86 | } | 79 | } |
| 87 | 80 | ||
| 88 | error UnexpectedEof; | ||
| 89 | test "valid utf8" { | 81 | test "valid utf8" { |
| 90 | testValid("\x00", 0x0); | 82 | testValid("\x00", 0x0); |
| 91 | testValid("\x20", 0x20); | 83 | testValid("\x20", 0x20); |
| ... | @@ -161,7 +153,7 @@ fn testValid(bytes: []const u8, expected_codepoint: u32) void { | ... | @@ -161,7 +153,7 @@ fn testValid(bytes: []const u8, expected_codepoint: u32) void { |
| 161 | std.debug.assert((testDecode(bytes) catch unreachable) == expected_codepoint); | 153 | std.debug.assert((testDecode(bytes) catch unreachable) == expected_codepoint); |
| 162 | } | 154 | } |
| 163 | 155 | ||
| 164 | fn testDecode(bytes: []const u8) %u32 { | 156 | fn testDecode(bytes: []const u8) !u32 { |
| 165 | const length = try utf8ByteSequenceLength(bytes[0]); | 157 | const length = try utf8ByteSequenceLength(bytes[0]); |
| 166 | if (bytes.len < length) return error.UnexpectedEof; | 158 | if (bytes.len < length) return error.UnexpectedEof; |
| 167 | std.debug.assert(bytes.len == length); | 159 | std.debug.assert(bytes.len == length); |
test/cases/cast.zig+16-18| ... | @@ -32,7 +32,6 @@ fn funcWithConstPtrPtr(x: &const &i32) void { | ... | @@ -32,7 +32,6 @@ fn funcWithConstPtrPtr(x: &const &i32) void { |
| 32 | **x += 1; | 32 | **x += 1; |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | error ItBroke; | ||
| 36 | test "explicit cast from integer to error type" { | 35 | test "explicit cast from integer to error type" { |
| 37 | testCastIntToErr(error.ItBroke); | 36 | testCastIntToErr(error.ItBroke); |
| 38 | comptime testCastIntToErr(error.ItBroke); | 37 | comptime testCastIntToErr(error.ItBroke); |
| ... | @@ -75,7 +74,7 @@ test "string literal to &const []const u8" { | ... | @@ -75,7 +74,7 @@ test "string literal to &const []const u8" { |
| 75 | assert(mem.eql(u8, *x, "hello")); | 74 | assert(mem.eql(u8, *x, "hello")); |
| 76 | } | 75 | } |
| 77 | 76 | ||
| 78 | test "implicitly cast from T to %?T" { | 77 | test "implicitly cast from T to error!?T" { |
| 79 | castToMaybeTypeError(1); | 78 | castToMaybeTypeError(1); |
| 80 | comptime castToMaybeTypeError(1); | 79 | comptime castToMaybeTypeError(1); |
| 81 | } | 80 | } |
| ... | @@ -84,37 +83,37 @@ const A = struct { | ... | @@ -84,37 +83,37 @@ const A = struct { |
| 84 | }; | 83 | }; |
| 85 | fn castToMaybeTypeError(z: i32) void { | 84 | fn castToMaybeTypeError(z: i32) void { |
| 86 | const x = i32(1); | 85 | const x = i32(1); |
| 87 | const y: %?i32 = x; | 86 | const y: error!?i32 = x; |
| 88 | assert(??(try y) == 1); | 87 | assert(??(try y) == 1); |
| 89 | 88 | ||
| 90 | const f = z; | 89 | const f = z; |
| 91 | const g: %?i32 = f; | 90 | const g: error!?i32 = f; |
| 92 | 91 | ||
| 93 | const a = A{ .a = z }; | 92 | const a = A{ .a = z }; |
| 94 | const b: %?A = a; | 93 | const b: error!?A = a; |
| 95 | assert((??(b catch unreachable)).a == 1); | 94 | assert((??(b catch unreachable)).a == 1); |
| 96 | } | 95 | } |
| 97 | 96 | ||
| 98 | test "implicitly cast from int to %?T" { | 97 | test "implicitly cast from int to error!?T" { |
| 99 | implicitIntLitToMaybe(); | 98 | implicitIntLitToMaybe(); |
| 100 | comptime implicitIntLitToMaybe(); | 99 | comptime implicitIntLitToMaybe(); |
| 101 | } | 100 | } |
| 102 | fn implicitIntLitToMaybe() void { | 101 | fn implicitIntLitToMaybe() void { |
| 103 | const f: ?i32 = 1; | 102 | const f: ?i32 = 1; |
| 104 | const g: %?i32 = 1; | 103 | const g: error!?i32 = 1; |
| 105 | } | 104 | } |
| 106 | 105 | ||
| 107 | 106 | ||
| 108 | test "return null from fn() %?&T" { | 107 | test "return null from fn() error!?&T" { |
| 109 | const a = returnNullFromMaybeTypeErrorRef(); | 108 | const a = returnNullFromMaybeTypeErrorRef(); |
| 110 | const b = returnNullLitFromMaybeTypeErrorRef(); | 109 | const b = returnNullLitFromMaybeTypeErrorRef(); |
| 111 | assert((try a) == null and (try b) == null); | 110 | assert((try a) == null and (try b) == null); |
| 112 | } | 111 | } |
| 113 | fn returnNullFromMaybeTypeErrorRef() %?&A { | 112 | fn returnNullFromMaybeTypeErrorRef() error!?&A { |
| 114 | const a: ?&A = null; | 113 | const a: ?&A = null; |
| 115 | return a; | 114 | return a; |
| 116 | } | 115 | } |
| 117 | fn returnNullLitFromMaybeTypeErrorRef() %?&A { | 116 | fn returnNullLitFromMaybeTypeErrorRef() error!?&A { |
| 118 | return null; | 117 | return null; |
| 119 | } | 118 | } |
| 120 | 119 | ||
| ... | @@ -161,7 +160,7 @@ fn castToMaybeSlice() ?[]const u8 { | ... | @@ -161,7 +160,7 @@ fn castToMaybeSlice() ?[]const u8 { |
| 161 | } | 160 | } |
| 162 | 161 | ||
| 163 | 162 | ||
| 164 | test "implicitly cast from [0]T to %[]T" { | 163 | test "implicitly cast from [0]T to error![]T" { |
| 165 | testCastZeroArrayToErrSliceMut(); | 164 | testCastZeroArrayToErrSliceMut(); |
| 166 | comptime testCastZeroArrayToErrSliceMut(); | 165 | comptime testCastZeroArrayToErrSliceMut(); |
| 167 | } | 166 | } |
| ... | @@ -170,11 +169,11 @@ fn testCastZeroArrayToErrSliceMut() void { | ... | @@ -170,11 +169,11 @@ fn testCastZeroArrayToErrSliceMut() void { |
| 170 | assert((gimmeErrOrSlice() catch unreachable).len == 0); | 169 | assert((gimmeErrOrSlice() catch unreachable).len == 0); |
| 171 | } | 170 | } |
| 172 | 171 | ||
| 173 | fn gimmeErrOrSlice() %[]u8 { | 172 | fn gimmeErrOrSlice() error![]u8 { |
| 174 | return []u8{}; | 173 | return []u8{}; |
| 175 | } | 174 | } |
| 176 | 175 | ||
| 177 | test "peer type resolution: [0]u8, []const u8, and %[]u8" { | 176 | test "peer type resolution: [0]u8, []const u8, and error![]u8" { |
| 178 | { | 177 | { |
| 179 | var data = "hi"; | 178 | var data = "hi"; |
| 180 | const slice = data[0..]; | 179 | const slice = data[0..]; |
| ... | @@ -188,7 +187,7 @@ test "peer type resolution: [0]u8, []const u8, and %[]u8" { | ... | @@ -188,7 +187,7 @@ test "peer type resolution: [0]u8, []const u8, and %[]u8" { |
| 188 | assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); | 187 | assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); |
| 189 | } | 188 | } |
| 190 | } | 189 | } |
| 191 | fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) %[]u8 { | 190 | fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) error![]u8 { |
| 192 | if (a) { | 191 | if (a) { |
| 193 | return []u8{}; | 192 | return []u8{}; |
| 194 | } | 193 | } |
| ... | @@ -230,7 +229,7 @@ fn foo(args: ...) void { | ... | @@ -230,7 +229,7 @@ fn foo(args: ...) void { |
| 230 | 229 | ||
| 231 | 230 | ||
| 232 | test "peer type resolution: error and [N]T" { | 231 | test "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 |
| 234 | //assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); | 233 | //assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); |
| 235 | //comptime assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); | 234 | //comptime assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); |
| 236 | 235 | ||
| ... | @@ -238,14 +237,13 @@ test "peer type resolution: error and [N]T" { | ... | @@ -238,14 +237,13 @@ test "peer type resolution: error and [N]T" { |
| 238 | comptime assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); | 237 | comptime assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); |
| 239 | } | 238 | } |
| 240 | 239 | ||
| 241 | error BadValue; | 240 | //fn testPeerErrorAndArray(x: u8) error![]const u8 { |
| 242 | //fn testPeerErrorAndArray(x: u8) %[]const u8 { | ||
| 243 | // return switch (x) { | 241 | // return switch (x) { |
| 244 | // 0x00 => "OK", | 242 | // 0x00 => "OK", |
| 245 | // else => error.BadValue, | 243 | // else => error.BadValue, |
| 246 | // }; | 244 | // }; |
| 247 | //} | 245 | //} |
| 248 | fn testPeerErrorAndArray2(x: u8) %[]const u8 { | 246 | fn testPeerErrorAndArray2(x: u8) error![]const u8 { |
| 249 | return switch (x) { | 247 | return switch (x) { |
| 250 | 0x00 => "OK", | 248 | 0x00 => "OK", |
| 251 | 0x01 => "OKK", | 249 | 0x01 => "OKK", |
test/cases/defer.zig+1-3| ... | @@ -3,9 +3,7 @@ const assert = @import("std").debug.assert; | ... | @@ -3,9 +3,7 @@ const assert = @import("std").debug.assert; |
| 3 | var result: [3]u8 = undefined; | 3 | var result: [3]u8 = undefined; |
| 4 | var index: usize = undefined; | 4 | var index: usize = undefined; |
| 5 | 5 | ||
| 6 | error FalseNotAllowed; | 6 | fn runSomeErrorDefers(x: bool) !bool { |
| 7 | |||
| 8 | fn runSomeErrorDefers(x: bool) %bool { | ||
| 9 | index = 0; | 7 | index = 0; |
| 10 | defer {result[index] = 'a'; index += 1;} | 8 | defer {result[index] = 'a'; index += 1;} |
| 11 | errdefer {result[index] = 'b'; index += 1;} | 9 | errdefer {result[index] = 'b'; index += 1;} |
test/cases/enum_with_members.zig+1-1| ... | @@ -6,7 +6,7 @@ const ET = union(enum) { | ... | @@ -6,7 +6,7 @@ const ET = union(enum) { |
| 6 | SINT: i32, | 6 | SINT: i32, |
| 7 | UINT: u32, | 7 | UINT: u32, |
| 8 | 8 | ||
| 9 | pub fn print(a: &const ET, buf: []u8) %usize { | 9 | pub fn print(a: &const ET, buf: []u8) error!usize { |
| 10 | return switch (*a) { | 10 | return switch (*a) { |
| 11 | ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0), | 11 | ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0), |
| 12 | ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0), | 12 | ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0), |
test/cases/error.zig+85-18| ... | @@ -1,16 +1,18 @@ | ... | @@ -1,16 +1,18 @@ |
| 1 | const assert = @import("std").debug.assert; | 1 | const std = @import("std"); |
| 2 | const mem = @import("std").mem; | 2 | const assert = std.debug.assert; |
| 3 | const mem = std.mem; | ||
| 4 | const builtin = @import("builtin"); | ||
| 3 | 5 | ||
| 4 | pub fn foo() %i32 { | 6 | pub fn foo() error!i32 { |
| 5 | const x = try bar(); | 7 | const x = try bar(); |
| 6 | return x + 1; | 8 | return x + 1; |
| 7 | } | 9 | } |
| 8 | 10 | ||
| 9 | pub fn bar() %i32 { | 11 | pub fn bar() error!i32 { |
| 10 | return 13; | 12 | return 13; |
| 11 | } | 13 | } |
| 12 | 14 | ||
| 13 | pub fn baz() %i32 { | 15 | pub fn baz() error!i32 { |
| 14 | const y = foo() catch 1234; | 16 | const y = foo() catch 1234; |
| 15 | return y + 1; | 17 | return y + 1; |
| 16 | } | 18 | } |
| ... | @@ -19,7 +21,6 @@ test "error wrapping" { | ... | @@ -19,7 +21,6 @@ test "error wrapping" { |
| 19 | assert((baz() catch unreachable) == 15); | 21 | assert((baz() catch unreachable) == 15); |
| 20 | } | 22 | } |
| 21 | 23 | ||
| 22 | error ItBroke; | ||
| 23 | fn gimmeItBroke() []const u8 { | 24 | fn gimmeItBroke() []const u8 { |
| 24 | return @errorName(error.ItBroke); | 25 | return @errorName(error.ItBroke); |
| 25 | } | 26 | } |
| ... | @@ -28,8 +29,6 @@ test "@errorName" { | ... | @@ -28,8 +29,6 @@ test "@errorName" { |
| 28 | assert(mem.eql(u8, @errorName(error.AnError), "AnError")); | 29 | assert(mem.eql(u8, @errorName(error.AnError), "AnError")); |
| 29 | assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName")); | 30 | assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName")); |
| 30 | } | 31 | } |
| 31 | error AnError; | ||
| 32 | error ALongerErrorName; | ||
| 33 | 32 | ||
| 34 | 33 | ||
| 35 | test "error values" { | 34 | test "error values" { |
| ... | @@ -37,16 +36,11 @@ test "error values" { | ... | @@ -37,16 +36,11 @@ test "error values" { |
| 37 | const b = i32(error.err2); | 36 | const b = i32(error.err2); |
| 38 | assert(a != b); | 37 | assert(a != b); |
| 39 | } | 38 | } |
| 40 | error err1; | ||
| 41 | error err2; | ||
| 42 | 39 | ||
| 43 | 40 | ||
| 44 | test "redefinition of error values allowed" { | 41 | test "redefinition of error values allowed" { |
| 45 | shouldBeNotEqual(error.AnError, error.SecondError); | 42 | shouldBeNotEqual(error.AnError, error.SecondError); |
| 46 | } | 43 | } |
| 47 | error AnError; | ||
| 48 | error AnError; | ||
| 49 | error SecondError; | ||
| 50 | fn shouldBeNotEqual(a: error, b: error) void { | 44 | fn shouldBeNotEqual(a: error, b: error) void { |
| 51 | if (a == b) unreachable; | 45 | if (a == b) unreachable; |
| 52 | } | 46 | } |
| ... | @@ -58,8 +52,7 @@ test "error binary operator" { | ... | @@ -58,8 +52,7 @@ test "error binary operator" { |
| 58 | assert(a == 3); | 52 | assert(a == 3); |
| 59 | assert(b == 10); | 53 | assert(b == 10); |
| 60 | } | 54 | } |
| 61 | error ItBroke; | 55 | fn errBinaryOperatorG(x: bool) error!isize { |
| 62 | fn errBinaryOperatorG(x: bool) %isize { | ||
| 63 | return if (x) error.ItBroke else isize(10); | 56 | return if (x) error.ItBroke else isize(10); |
| 64 | } | 57 | } |
| 65 | 58 | ||
| ... | @@ -68,18 +61,92 @@ test "unwrap simple value from error" { | ... | @@ -68,18 +61,92 @@ test "unwrap simple value from error" { |
| 68 | const i = unwrapSimpleValueFromErrorDo() catch unreachable; | 61 | const i = unwrapSimpleValueFromErrorDo() catch unreachable; |
| 69 | assert(i == 13); | 62 | assert(i == 13); |
| 70 | } | 63 | } |
| 71 | fn unwrapSimpleValueFromErrorDo() %isize { return 13; } | 64 | fn unwrapSimpleValueFromErrorDo() error!isize { return 13; } |
| 72 | 65 | ||
| 73 | 66 | ||
| 74 | test "error return in assignment" { | 67 | test "error return in assignment" { |
| 75 | doErrReturnInAssignment() catch unreachable; | 68 | doErrReturnInAssignment() catch unreachable; |
| 76 | } | 69 | } |
| 77 | 70 | ||
| 78 | fn doErrReturnInAssignment() %void { | 71 | fn doErrReturnInAssignment() error!void { |
| 79 | var x : i32 = undefined; | 72 | var x : i32 = undefined; |
| 80 | x = try makeANonErr(); | 73 | x = try makeANonErr(); |
| 81 | } | 74 | } |
| 82 | 75 | ||
| 83 | fn makeANonErr() %i32 { | 76 | fn makeANonErr() error!i32 { |
| 84 | return 1; | 77 | return 1; |
| 85 | } | 78 | } |
| 79 | |||
| 80 | test "error union type " { | ||
| 81 | testErrorUnionType(); | ||
| 82 | comptime testErrorUnionType(); | ||
| 83 | } | ||
| 84 | |||
| 85 | fn 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 | |||
| 93 | test "error set type " { | ||
| 94 | testErrorSetType(); | ||
| 95 | comptime testErrorSetType(); | ||
| 96 | } | ||
| 97 | |||
| 98 | const MyErrSet = error {OutOfMemory, FileNotFound}; | ||
| 99 | |||
| 100 | fn 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 | |||
| 113 | test "explicit error set cast" { | ||
| 114 | testExplicitErrorSetCast(Set1.A); | ||
| 115 | comptime testExplicitErrorSetCast(Set1.A); | ||
| 116 | } | ||
| 117 | |||
| 118 | const Set1 = error{A, B}; | ||
| 119 | const Set2 = error{A, C}; | ||
| 120 | |||
| 121 | fn testExplicitErrorSetCast(set1: Set1) void { | ||
| 122 | var x = Set2(set1); | ||
| 123 | var y = Set1(x); | ||
| 124 | assert(y == error.A); | ||
| 125 | } | ||
| 126 | |||
| 127 | test "comptime test error for empty error set" { | ||
| 128 | testComptimeTestErrorEmptySet(1234); | ||
| 129 | comptime testComptimeTestErrorEmptySet(1234); | ||
| 130 | } | ||
| 131 | |||
| 132 | const EmptyErrorSet = error {}; | ||
| 133 | |||
| 134 | fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void { | ||
| 135 | if (x) |v| assert(v == 1234) else |err| @compileError("bad"); | ||
| 136 | } | ||
| 137 | |||
| 138 | test "syntax: nullable operator in front of error union operator" { | ||
| 139 | comptime { | ||
| 140 | assert(?error!i32 == ?(error!i32)); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | test "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 | } | ||
| 148 | fn testErrToIntWithOnePossibleValue(x: error{A}, comptime value: u32) void { | ||
| 149 | if (u32(x) != value) { | ||
| 150 | @compileError("bad"); | ||
| 151 | } | ||
| 152 | } |
test/cases/ir_block_deps.zig+2-4| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | const assert = @import("std").debug.assert; | 1 | const assert = @import("std").debug.assert; |
| 2 | 2 | ||
| 3 | fn foo(id: u64) %i32 { | 3 | fn foo(id: u64) !i32 { |
| 4 | return switch (id) { | 4 | return switch (id) { |
| 5 | 1 => getErrInt(), | 5 | 1 => getErrInt(), |
| 6 | 2 => { | 6 | 2 => { |
| ... | @@ -11,9 +11,7 @@ fn foo(id: u64) %i32 { | ... | @@ -11,9 +11,7 @@ fn foo(id: u64) %i32 { |
| 11 | }; | 11 | }; |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | fn getErrInt() %i32 { return 0; } | 14 | fn getErrInt() error!i32 { return 0; } |
| 15 | |||
| 16 | error ItBroke; | ||
| 17 | 15 | ||
| 18 | test "ir block deps" { | 16 | test "ir block deps" { |
| 19 | assert((foo(1) catch unreachable) == 0); | 17 | assert((foo(1) catch unreachable) == 0); |
test/cases/misc.zig+4-4| ... | @@ -262,7 +262,7 @@ test "generic malloc free" { | ... | @@ -262,7 +262,7 @@ test "generic malloc free" { |
| 262 | memFree(u8, a); | 262 | memFree(u8, a); |
| 263 | } | 263 | } |
| 264 | const some_mem : [100]u8 = undefined; | 264 | const some_mem : [100]u8 = undefined; |
| 265 | fn memAlloc(comptime T: type, n: usize) %[]T { | 265 | fn memAlloc(comptime T: type, n: usize) error![]T { |
| 266 | return @ptrCast(&T, &some_mem[0])[0..n]; | 266 | return @ptrCast(&T, &some_mem[0])[0..n]; |
| 267 | } | 267 | } |
| 268 | fn memFree(comptime T: type, memory: []T) void { } | 268 | fn memFree(comptime T: type, memory: []T) void { } |
| ... | @@ -419,7 +419,7 @@ test "cast slice to u8 slice" { | ... | @@ -419,7 +419,7 @@ test "cast slice to u8 slice" { |
| 419 | test "pointer to void return type" { | 419 | test "pointer to void return type" { |
| 420 | testPointerToVoidReturnType() catch unreachable; | 420 | testPointerToVoidReturnType() catch unreachable; |
| 421 | } | 421 | } |
| 422 | fn testPointerToVoidReturnType() %void { | 422 | fn testPointerToVoidReturnType() error!void { |
| 423 | const a = testPointerToVoidReturnType2(); | 423 | const a = testPointerToVoidReturnType2(); |
| 424 | return *a; | 424 | return *a; |
| 425 | } | 425 | } |
| ... | @@ -475,8 +475,8 @@ test "@typeId" { | ... | @@ -475,8 +475,8 @@ test "@typeId" { |
| 475 | assert(@typeId(@typeOf(undefined)) == Tid.UndefinedLiteral); | 475 | assert(@typeId(@typeOf(undefined)) == Tid.UndefinedLiteral); |
| 476 | assert(@typeId(@typeOf(null)) == Tid.NullLiteral); | 476 | assert(@typeId(@typeOf(null)) == Tid.NullLiteral); |
| 477 | assert(@typeId(?i32) == Tid.Nullable); | 477 | assert(@typeId(?i32) == Tid.Nullable); |
| 478 | assert(@typeId(%i32) == Tid.ErrorUnion); | 478 | assert(@typeId(error!i32) == Tid.ErrorUnion); |
| 479 | assert(@typeId(error) == Tid.Error); | 479 | assert(@typeId(error) == Tid.ErrorSet); |
| 480 | assert(@typeId(AnEnum) == Tid.Enum); | 480 | assert(@typeId(AnEnum) == Tid.Enum); |
| 481 | assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum); | 481 | assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum); |
| 482 | assert(@typeId(AUnionEnum) == Tid.Union); | 482 | assert(@typeId(AUnionEnum) == Tid.Union); |
test/cases/reflection.zig+1-1| ... | @@ -5,7 +5,7 @@ test "reflection: array, pointer, nullable, error union type child" { | ... | @@ -5,7 +5,7 @@ test "reflection: array, pointer, nullable, error union type child" { |
| 5 | comptime { | 5 | comptime { |
| 6 | assert(([10]u8).Child == u8); | 6 | assert(([10]u8).Child == u8); |
| 7 | assert((&u8).Child == u8); | 7 | assert((&u8).Child == u8); |
| 8 | assert((%u8).Child == u8); | 8 | assert((error!u8).Payload == u8); |
| 9 | assert((?u8).Child == u8); | 9 | assert((?u8).Child == u8); |
| 10 | } | 10 | } |
| 11 | } | 11 | } |
test/cases/switch.zig+1-1| ... | @@ -225,7 +225,7 @@ fn switchWithUnreachable(x: i32) i32 { | ... | @@ -225,7 +225,7 @@ fn switchWithUnreachable(x: i32) i32 { |
| 225 | return 10; | 225 | return 10; |
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | fn return_a_number() %i32 { | 228 | fn return_a_number() error!i32 { |
| 229 | return 1; | 229 | return 1; |
| 230 | } | 230 | } |
| 231 | 231 |
test/cases/switch_prong_err_enum.zig+2-4| ... | @@ -2,19 +2,17 @@ const assert = @import("std").debug.assert; | ... | @@ -2,19 +2,17 @@ const assert = @import("std").debug.assert; |
| 2 | 2 | ||
| 3 | var read_count: u64 = 0; | 3 | var read_count: u64 = 0; |
| 4 | 4 | ||
| 5 | fn readOnce() %u64 { | 5 | fn readOnce() error!u64 { |
| 6 | read_count += 1; | 6 | read_count += 1; |
| 7 | return read_count; | 7 | return read_count; |
| 8 | } | 8 | } |
| 9 | 9 | ||
| 10 | error InvalidDebugInfo; | ||
| 11 | |||
| 12 | const FormValue = union(enum) { | 10 | const FormValue = union(enum) { |
| 13 | Address: u64, | 11 | Address: u64, |
| 14 | Other: bool, | 12 | Other: bool, |
| 15 | }; | 13 | }; |
| 16 | 14 | ||
| 17 | fn doThing(form_id: u64) %FormValue { | 15 | fn doThing(form_id: u64) error!FormValue { |
| 18 | return switch (form_id) { | 16 | return switch (form_id) { |
| 19 | 17 => FormValue { .Address = try readOnce() }, | 17 | 17 => FormValue { .Address = try readOnce() }, |
| 20 | else => error.InvalidDebugInfo, | 18 | else => error.InvalidDebugInfo, |
test/cases/switch_prong_implicit_cast.zig+1-3| ... | @@ -5,9 +5,7 @@ const FormValue = union(enum) { | ... | @@ -5,9 +5,7 @@ const FormValue = union(enum) { |
| 5 | Two: bool, | 5 | Two: bool, |
| 6 | }; | 6 | }; |
| 7 | 7 | ||
| 8 | error Whatever; | 8 | fn foo(id: u64) !FormValue { |
| 9 | |||
| 10 | fn foo(id: u64) %FormValue { | ||
| 11 | return switch (id) { | 9 | return switch (id) { |
| 12 | 2 => FormValue { .Two = true }, | 10 | 2 => FormValue { .Two = true }, |
| 13 | 1 => FormValue { .One = {} }, | 11 | 1 => FormValue { .One = {} }, |
test/cases/try.zig+2-5| ... | @@ -17,10 +17,7 @@ fn tryOnErrorUnionImpl() void { | ... | @@ -17,10 +17,7 @@ fn tryOnErrorUnionImpl() void { |
| 17 | assert(x == 11); | 17 | assert(x == 11); |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | error ItBroke; | 20 | fn returnsTen() error!i32 { |
| 21 | error NoMem; | ||
| 22 | error CrappedOut; | ||
| 23 | fn returnsTen() %i32 { | ||
| 24 | return 10; | 21 | return 10; |
| 25 | } | 22 | } |
| 26 | 23 | ||
| ... | @@ -32,7 +29,7 @@ test "try without vars" { | ... | @@ -32,7 +29,7 @@ test "try without vars" { |
| 32 | assert(result2 == 1); | 29 | assert(result2 == 1); |
| 33 | } | 30 | } |
| 34 | 31 | ||
| 35 | fn failIfTrue(ok: bool) %void { | 32 | fn failIfTrue(ok: bool) error!void { |
| 36 | if (ok) { | 33 | if (ok) { |
| 37 | return error.ItBroke; | 34 | return error.ItBroke; |
| 38 | } else { | 35 | } else { |
test/cases/union.zig+1-1| ... | @@ -13,7 +13,7 @@ const Agg = struct { | ... | @@ -13,7 +13,7 @@ const Agg = struct { |
| 13 | const v1 = Value { .Int = 1234 }; | 13 | const v1 = Value { .Int = 1234 }; |
| 14 | const v2 = Value { .Array = []u8{3} ** 9 }; | 14 | const v2 = Value { .Array = []u8{3} ** 9 }; |
| 15 | 15 | ||
| 16 | const err = (%Agg)(Agg { | 16 | const err = (error!Agg)(Agg { |
| 17 | .val1 = v1, | 17 | .val1 = v1, |
| 18 | .val2 = v2, | 18 | .val2 = v2, |
| 19 | }); | 19 | }); |
test/cases/while.zig+4-6| ... | @@ -50,7 +50,7 @@ fn runContinueAndBreakTest() void { | ... | @@ -50,7 +50,7 @@ fn runContinueAndBreakTest() void { |
| 50 | test "return with implicit cast from while loop" { | 50 | test "return with implicit cast from while loop" { |
| 51 | returnWithImplicitCastFromWhileLoopTest() catch unreachable; | 51 | returnWithImplicitCastFromWhileLoopTest() catch unreachable; |
| 52 | } | 52 | } |
| 53 | fn returnWithImplicitCastFromWhileLoopTest() %void { | 53 | fn returnWithImplicitCastFromWhileLoopTest() error!void { |
| 54 | while (true) { | 54 | while (true) { |
| 55 | return; | 55 | return; |
| 56 | } | 56 | } |
| ... | @@ -116,8 +116,7 @@ test "while with error union condition" { | ... | @@ -116,8 +116,7 @@ test "while with error union condition" { |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | var numbers_left: i32 = undefined; | 118 | var numbers_left: i32 = undefined; |
| 119 | error OutOfNumbers; | 119 | fn getNumberOrErr() error!i32 { |
| 120 | fn getNumberOrErr() %i32 { | ||
| 121 | return if (numbers_left == 0) | 120 | return if (numbers_left == 0) |
| 122 | error.OutOfNumbers | 121 | error.OutOfNumbers |
| 123 | else x: { | 122 | else x: { |
| ... | @@ -205,8 +204,7 @@ fn testContinueOuter() void { | ... | @@ -205,8 +204,7 @@ fn testContinueOuter() void { |
| 205 | 204 | ||
| 206 | fn returnNull() ?i32 { return null; } | 205 | fn returnNull() ?i32 { return null; } |
| 207 | fn returnMaybe(x: i32) ?i32 { return x; } | 206 | fn returnMaybe(x: i32) ?i32 { return x; } |
| 208 | error YouWantedAnError; | 207 | fn returnError() error!i32 { return error.YouWantedAnError; } |
| 209 | fn returnError() %i32 { return error.YouWantedAnError; } | 208 | fn returnSuccess(x: i32) error!i32 { return x; } |
| 210 | fn returnSuccess(x: i32) %i32 { return x; } | ||
| 211 | fn returnFalse() bool { return false; } | 209 | fn returnFalse() bool { return false; } |
| 212 | fn returnTrue() bool { return true; } | 210 | fn returnTrue() bool { return true; } |
test/compare_output.zig+17-18| ... | @@ -15,7 +15,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -15,7 +15,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 15 | \\use @import("std").io; | 15 | \\use @import("std").io; |
| 16 | \\use @import("foo.zig"); | 16 | \\use @import("foo.zig"); |
| 17 | \\ | 17 | \\ |
| 18 | \\pub fn main() %void { | 18 | \\pub fn main() void { |
| 19 | \\ privateFunction(); | 19 | \\ privateFunction(); |
| 20 | \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream); | 20 | \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream); |
| 21 | \\ stdout.print("OK 2\n") catch unreachable; | 21 | \\ stdout.print("OK 2\n") catch unreachable; |
| ... | @@ -49,7 +49,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -49,7 +49,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 49 | \\use @import("foo.zig"); | 49 | \\use @import("foo.zig"); |
| 50 | \\use @import("bar.zig"); | 50 | \\use @import("bar.zig"); |
| 51 | \\ | 51 | \\ |
| 52 | \\pub fn main() %void { | 52 | \\pub fn main() void { |
| 53 | \\ foo_function(); | 53 | \\ foo_function(); |
| 54 | \\ bar_function(); | 54 | \\ bar_function(); |
| 55 | \\} | 55 | \\} |
| ... | @@ -89,7 +89,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -89,7 +89,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 89 | var tc = cases.create("two files use import each other", | 89 | var tc = cases.create("two files use import each other", |
| 90 | \\use @import("a.zig"); | 90 | \\use @import("a.zig"); |
| 91 | \\ | 91 | \\ |
| 92 | \\pub fn main() %void { | 92 | \\pub fn main() void { |
| 93 | \\ ok(); | 93 | \\ ok(); |
| 94 | \\} | 94 | \\} |
| 95 | , "OK\n"); | 95 | , "OK\n"); |
| ... | @@ -118,7 +118,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -118,7 +118,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 118 | cases.add("hello world without libc", | 118 | cases.add("hello world without libc", |
| 119 | \\const io = @import("std").io; | 119 | \\const io = @import("std").io; |
| 120 | \\ | 120 | \\ |
| 121 | \\pub fn main() %void { | 121 | \\pub fn main() void { |
| 122 | \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream); | 122 | \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream); |
| 123 | \\ stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable; | 123 | \\ stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable; |
| 124 | \\} | 124 | \\} |
| ... | @@ -268,7 +268,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -268,7 +268,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 268 | \\const z = io.stdin_fileno; | 268 | \\const z = io.stdin_fileno; |
| 269 | \\const x : @typeOf(y) = 1234; | 269 | \\const x : @typeOf(y) = 1234; |
| 270 | \\const y : u16 = 5678; | 270 | \\const y : u16 = 5678; |
| 271 | \\pub fn main() %void { | 271 | \\pub fn main() void { |
| 272 | \\ var x_local : i32 = print_ok(x); | 272 | \\ var x_local : i32 = print_ok(x); |
| 273 | \\} | 273 | \\} |
| 274 | \\fn print_ok(val: @typeOf(x)) @typeOf(foo) { | 274 | \\fn print_ok(val: @typeOf(x)) @typeOf(foo) { |
| ... | @@ -351,7 +351,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -351,7 +351,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 351 | \\ fn method(b: &const Bar) bool { return true; } | 351 | \\ fn method(b: &const Bar) bool { return true; } |
| 352 | \\}; | 352 | \\}; |
| 353 | \\ | 353 | \\ |
| 354 | \\pub fn main() %void { | 354 | \\pub fn main() void { |
| 355 | \\ const bar = Bar {.field2 = 13,}; | 355 | \\ const bar = Bar {.field2 = 13,}; |
| 356 | \\ const foo = Foo {.field1 = bar,}; | 356 | \\ const foo = Foo {.field1 = bar,}; |
| 357 | \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream); | 357 | \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream); |
| ... | @@ -367,7 +367,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -367,7 +367,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 367 | 367 | ||
| 368 | cases.add("defer with only fallthrough", | 368 | cases.add("defer with only fallthrough", |
| 369 | \\const io = @import("std").io; | 369 | \\const io = @import("std").io; |
| 370 | \\pub fn main() %void { | 370 | \\pub fn main() void { |
| 371 | \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream); | 371 | \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream); |
| 372 | \\ stdout.print("before\n") catch unreachable; | 372 | \\ stdout.print("before\n") catch unreachable; |
| 373 | \\ defer stdout.print("defer1\n") catch unreachable; | 373 | \\ defer stdout.print("defer1\n") catch unreachable; |
| ... | @@ -380,7 +380,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -380,7 +380,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 380 | cases.add("defer with return", | 380 | cases.add("defer with return", |
| 381 | \\const io = @import("std").io; | 381 | \\const io = @import("std").io; |
| 382 | \\const os = @import("std").os; | 382 | \\const os = @import("std").os; |
| 383 | \\pub fn main() %void { | 383 | \\pub fn main() void { |
| 384 | \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream); | 384 | \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream); |
| 385 | \\ stdout.print("before\n") catch unreachable; | 385 | \\ stdout.print("before\n") catch unreachable; |
| 386 | \\ defer stdout.print("defer1\n") catch unreachable; | 386 | \\ defer stdout.print("defer1\n") catch unreachable; |
| ... | @@ -394,10 +394,10 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -394,10 +394,10 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 394 | 394 | ||
| 395 | cases.add("errdefer and it fails", | 395 | cases.add("errdefer and it fails", |
| 396 | \\const io = @import("std").io; | 396 | \\const io = @import("std").io; |
| 397 | \\pub fn main() %void { | 397 | \\pub fn main() void { |
| 398 | \\ do_test() catch return; | 398 | \\ do_test() catch return; |
| 399 | \\} | 399 | \\} |
| 400 | \\fn do_test() %void { | 400 | \\fn do_test() !void { |
| 401 | \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream); | 401 | \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream); |
| 402 | \\ stdout.print("before\n") catch unreachable; | 402 | \\ stdout.print("before\n") catch unreachable; |
| 403 | \\ defer stdout.print("defer1\n") catch unreachable; | 403 | \\ defer stdout.print("defer1\n") catch unreachable; |
| ... | @@ -406,18 +406,17 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -406,18 +406,17 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 406 | \\ defer stdout.print("defer3\n") catch unreachable; | 406 | \\ defer stdout.print("defer3\n") catch unreachable; |
| 407 | \\ stdout.print("after\n") catch unreachable; | 407 | \\ stdout.print("after\n") catch unreachable; |
| 408 | \\} | 408 | \\} |
| 409 | \\error IToldYouItWouldFail; | 409 | \\fn its_gonna_fail() !void { |
| 410 | \\fn its_gonna_fail() %void { | ||
| 411 | \\ return error.IToldYouItWouldFail; | 410 | \\ return error.IToldYouItWouldFail; |
| 412 | \\} | 411 | \\} |
| 413 | , "before\ndeferErr\ndefer1\n"); | 412 | , "before\ndeferErr\ndefer1\n"); |
| 414 | 413 | ||
| 415 | cases.add("errdefer and it passes", | 414 | cases.add("errdefer and it passes", |
| 416 | \\const io = @import("std").io; | 415 | \\const io = @import("std").io; |
| 417 | \\pub fn main() %void { | 416 | \\pub fn main() void { |
| 418 | \\ do_test() catch return; | 417 | \\ do_test() catch return; |
| 419 | \\} | 418 | \\} |
| 420 | \\fn do_test() %void { | 419 | \\fn do_test() !void { |
| 421 | \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream); | 420 | \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream); |
| 422 | \\ stdout.print("before\n") catch unreachable; | 421 | \\ stdout.print("before\n") catch unreachable; |
| 423 | \\ defer stdout.print("defer1\n") catch unreachable; | 422 | \\ defer stdout.print("defer1\n") catch unreachable; |
| ... | @@ -426,7 +425,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -426,7 +425,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 426 | \\ defer stdout.print("defer3\n") catch unreachable; | 425 | \\ defer stdout.print("defer3\n") catch unreachable; |
| 427 | \\ stdout.print("after\n") catch unreachable; | 426 | \\ stdout.print("after\n") catch unreachable; |
| 428 | \\} | 427 | \\} |
| 429 | \\fn its_gonna_pass() %void { } | 428 | \\fn its_gonna_pass() error!void { } |
| 430 | , "before\nafter\ndefer3\ndefer1\n"); | 429 | , "before\nafter\ndefer3\ndefer1\n"); |
| 431 | 430 | ||
| 432 | cases.addCase(x: { | 431 | cases.addCase(x: { |
| ... | @@ -434,7 +433,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -434,7 +433,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 434 | \\const foo_txt = @embedFile("foo.txt"); | 433 | \\const foo_txt = @embedFile("foo.txt"); |
| 435 | \\const io = @import("std").io; | 434 | \\const io = @import("std").io; |
| 436 | \\ | 435 | \\ |
| 437 | \\pub fn main() %void { | 436 | \\pub fn main() void { |
| 438 | \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream); | 437 | \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream); |
| 439 | \\ stdout.print(foo_txt) catch unreachable; | 438 | \\ stdout.print(foo_txt) catch unreachable; |
| 440 | \\} | 439 | \\} |
| ... | @@ -452,7 +451,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -452,7 +451,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 452 | \\const os = std.os; | 451 | \\const os = std.os; |
| 453 | \\const allocator = std.debug.global_allocator; | 452 | \\const allocator = std.debug.global_allocator; |
| 454 | \\ | 453 | \\ |
| 455 | \\pub fn main() %void { | 454 | \\pub fn main() !void { |
| 456 | \\ var args_it = os.args(); | 455 | \\ var args_it = os.args(); |
| 457 | \\ var stdout_file = try io.getStdOut(); | 456 | \\ var stdout_file = try io.getStdOut(); |
| 458 | \\ var stdout_adapter = io.FileOutStream.init(&stdout_file); | 457 | \\ var stdout_adapter = io.FileOutStream.init(&stdout_file); |
| ... | @@ -493,7 +492,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -493,7 +492,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 493 | \\const os = std.os; | 492 | \\const os = std.os; |
| 494 | \\const allocator = std.debug.global_allocator; | 493 | \\const allocator = std.debug.global_allocator; |
| 495 | \\ | 494 | \\ |
| 496 | \\pub fn main() %void { | 495 | \\pub fn main() !void { |
| 497 | \\ var args_it = os.args(); | 496 | \\ var args_it = os.args(); |
| 498 | \\ var stdout_file = try io.getStdOut(); | 497 | \\ var stdout_file = try io.getStdOut(); |
| 499 | \\ var stdout_adapter = io.FileOutStream.init(&stdout_file); | 498 | \\ var stdout_adapter = io.FileOutStream.init(&stdout_file); |
test/compile_errors.zig+219-18| ... | @@ -1,6 +1,208 @@ | ... | @@ -1,6 +1,208 @@ |
| 1 | const tests = @import("tests.zig"); | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | ||
| 3 | pub fn addCases(cases: &tests.CompileErrorContext) void { | 3 | pub fn addCases(cases: &tests.CompileErrorContext) void { |
| 4 | cases.add("inferred error set with no returned error", | ||
| 5 | \\export fn entry() void { | ||
| 6 | \\ foo() catch unreachable; | ||
| 7 | \\} | ||
| 8 | \\fn foo() !void { | ||
| 9 | \\} | ||
| 10 | , | ||
| 11 | ".tmp_source.zig:4:11: error: function with inferred error set must return at least one possible error"); | ||
| 12 | |||
| 13 | cases.add("error not handled in switch", | ||
| 14 | \\export fn entry() void { | ||
| 15 | \\ foo(452) catch |err| switch (err) { | ||
| 16 | \\ error.Foo => {}, | ||
| 17 | \\ }; | ||
| 18 | \\} | ||
| 19 | \\fn foo(x: i32) !void { | ||
| 20 | \\ switch (x) { | ||
| 21 | \\ 0 ... 10 => return error.Foo, | ||
| 22 | \\ 11 ... 20 => return error.Bar, | ||
| 23 | \\ 21 ... 30 => return error.Baz, | ||
| 24 | \\ else => {}, | ||
| 25 | \\ } | ||
| 26 | \\} | ||
| 27 | , | ||
| 28 | ".tmp_source.zig:2:26: error: error.Baz not handled in switch", | ||
| 29 | ".tmp_source.zig:2:26: error: error.Bar not handled in switch"); | ||
| 30 | |||
| 31 | cases.add("duplicate error in switch", | ||
| 32 | \\export fn entry() void { | ||
| 33 | \\ foo(452) catch |err| switch (err) { | ||
| 34 | \\ error.Foo => {}, | ||
| 35 | \\ error.Bar => {}, | ||
| 36 | \\ error.Foo => {}, | ||
| 37 | \\ else => {}, | ||
| 38 | \\ }; | ||
| 39 | \\} | ||
| 40 | \\fn foo(x: i32) !void { | ||
| 41 | \\ switch (x) { | ||
| 42 | \\ 0 ... 10 => return error.Foo, | ||
| 43 | \\ 11 ... 20 => return error.Bar, | ||
| 44 | \\ else => {}, | ||
| 45 | \\ } | ||
| 46 | \\} | ||
| 47 | , | ||
| 48 | ".tmp_source.zig:5:14: error: duplicate switch value: '@typeOf(foo).ReturnType.ErrorSet.Foo'", | ||
| 49 | ".tmp_source.zig:3:14: note: other value is here"); | ||
| 50 | |||
| 51 | cases.add("range operator in switch used on error set", | ||
| 52 | \\export fn entry() void { | ||
| 53 | \\ try foo(452) catch |err| switch (err) { | ||
| 54 | \\ error.A ... error.B => {}, | ||
| 55 | \\ else => {}, | ||
| 56 | \\ }; | ||
| 57 | \\} | ||
| 58 | \\fn foo(x: i32) !void { | ||
| 59 | \\ switch (x) { | ||
| 60 | \\ 0 ... 10 => return error.Foo, | ||
| 61 | \\ 11 ... 20 => return error.Bar, | ||
| 62 | \\ else => {}, | ||
| 63 | \\ } | ||
| 64 | \\} | ||
| 65 | , | ||
| 66 | ".tmp_source.zig:3:17: error: operator not allowed for errors"); | ||
| 67 | |||
| 68 | cases.add("inferring error set of function pointer", | ||
| 69 | \\comptime { | ||
| 70 | \\ const z: ?fn()!void = null; | ||
| 71 | \\} | ||
| 72 | , | ||
| 73 | ".tmp_source.zig:2:15: error: inferring error set of return type valid only for function definitions"); | ||
| 74 | |||
| 75 | cases.add("access non-existent member of error set", | ||
| 76 | \\const Foo = error{A}; | ||
| 77 | \\comptime { | ||
| 78 | \\ const z = Foo.Bar; | ||
| 79 | \\} | ||
| 80 | , | ||
| 81 | ".tmp_source.zig:3:18: error: no error named 'Bar' in 'Foo'"); | ||
| 82 | |||
| 83 | cases.add("error union operator with non error set LHS", | ||
| 84 | \\comptime { | ||
| 85 | \\ const z = i32!i32; | ||
| 86 | \\} | ||
| 87 | , | ||
| 88 | ".tmp_source.zig:2:15: error: expected error set type, found type 'i32'"); | ||
| 89 | |||
| 90 | cases.add("error equality but sets have no common members", | ||
| 91 | \\const Set1 = error{A, C}; | ||
| 92 | \\const Set2 = error{B, D}; | ||
| 93 | \\export fn entry() void { | ||
| 94 | \\ foo(Set1.A); | ||
| 95 | \\} | ||
| 96 | \\fn foo(x: Set1) void { | ||
| 97 | \\ if (x == Set2.B) { | ||
| 98 | \\ | ||
| 99 | \\ } | ||
| 100 | \\} | ||
| 101 | , | ||
| 102 | ".tmp_source.zig:7:11: error: error sets 'Set1' and 'Set2' have no common errors"); | ||
| 103 | |||
| 104 | cases.add("only equality binary operator allowed for error sets", | ||
| 105 | \\comptime { | ||
| 106 | \\ const z = error.A > error.B; | ||
| 107 | \\} | ||
| 108 | , | ||
| 109 | ".tmp_source.zig:2:23: error: operator not allowed for errors"); | ||
| 110 | |||
| 111 | cases.add("explicit error set cast known at comptime violates error sets", | ||
| 112 | \\const Set1 = error {A, B}; | ||
| 113 | \\const Set2 = error {A, C}; | ||
| 114 | \\comptime { | ||
| 115 | \\ var x = Set1.B; | ||
| 116 | \\ var y = Set2(x); | ||
| 117 | \\} | ||
| 118 | , | ||
| 119 | ".tmp_source.zig:5:17: error: error.B not a member of error set 'Set2'"); | ||
| 120 | |||
| 121 | cases.add("cast error union of global error set to error union of smaller error set", | ||
| 122 | \\const SmallErrorSet = error{A}; | ||
| 123 | \\export fn entry() void { | ||
| 124 | \\ var x: SmallErrorSet!i32 = foo(); | ||
| 125 | \\} | ||
| 126 | \\fn foo() error!i32 { | ||
| 127 | \\ return error.B; | ||
| 128 | \\} | ||
| 129 | , | ||
| 130 | ".tmp_source.zig:3:35: error: expected 'SmallErrorSet!i32', found 'error!i32'", | ||
| 131 | ".tmp_source.zig:3:35: note: unable to cast global error set into smaller set"); | ||
| 132 | |||
| 133 | cases.add("cast global error set to error set", | ||
| 134 | \\const SmallErrorSet = error{A}; | ||
| 135 | \\export fn entry() void { | ||
| 136 | \\ var x: SmallErrorSet = foo(); | ||
| 137 | \\} | ||
| 138 | \\fn foo() error { | ||
| 139 | \\ return error.B; | ||
| 140 | \\} | ||
| 141 | , | ||
| 142 | ".tmp_source.zig:3:31: error: expected 'SmallErrorSet', found 'error'", | ||
| 143 | ".tmp_source.zig:3:31: note: unable to cast global error set into smaller set"); | ||
| 144 | |||
| 145 | cases.add("recursive inferred error set", | ||
| 146 | \\export fn entry() void { | ||
| 147 | \\ foo() catch unreachable; | ||
| 148 | \\} | ||
| 149 | \\fn foo() !void { | ||
| 150 | \\ try foo(); | ||
| 151 | \\} | ||
| 152 | , | ||
| 153 | ".tmp_source.zig:5:5: error: cannot resolve inferred error set '@typeOf(foo).ReturnType.ErrorSet': function 'foo' not fully analyzed yet"); | ||
| 154 | |||
| 155 | cases.add("implicit cast of error set not a subset", | ||
| 156 | \\const Set1 = error{A, B}; | ||
| 157 | \\const Set2 = error{A, C}; | ||
| 158 | \\export fn entry() void { | ||
| 159 | \\ foo(Set1.B); | ||
| 160 | \\} | ||
| 161 | \\fn foo(set1: Set1) void { | ||
| 162 | \\ var x: Set2 = set1; | ||
| 163 | \\} | ||
| 164 | , | ||
| 165 | ".tmp_source.zig:7:19: error: expected 'Set2', found 'Set1'", | ||
| 166 | ".tmp_source.zig:1:23: note: 'error.B' not a member of destination error set"); | ||
| 167 | |||
| 168 | cases.add("int to err global invalid number", | ||
| 169 | \\const Set1 = error{A, B}; | ||
| 170 | \\comptime { | ||
| 171 | \\ var x: usize = 3; | ||
| 172 | \\ var y = error(x); | ||
| 173 | \\} | ||
| 174 | , | ||
| 175 | ".tmp_source.zig:4:18: error: integer value 3 represents no error"); | ||
| 176 | |||
| 177 | cases.add("int to err non global invalid number", | ||
| 178 | \\const Set1 = error{A, B}; | ||
| 179 | \\const Set2 = error{A, C}; | ||
| 180 | \\comptime { | ||
| 181 | \\ var x = usize(Set1.B); | ||
| 182 | \\ var y = Set2(x); | ||
| 183 | \\} | ||
| 184 | , | ||
| 185 | ".tmp_source.zig:5:17: error: integer value 2 represents no error in 'Set2'"); | ||
| 186 | |||
| 187 | cases.add("@memberCount of error", | ||
| 188 | \\comptime { | ||
| 189 | \\ _ = @memberCount(error); | ||
| 190 | \\} | ||
| 191 | , | ||
| 192 | ".tmp_source.zig:2:9: error: global error set member count not available at comptime"); | ||
| 193 | |||
| 194 | cases.add("duplicate error value in error set", | ||
| 195 | \\const Foo = error { | ||
| 196 | \\ Bar, | ||
| 197 | \\ Bar, | ||
| 198 | \\}; | ||
| 199 | \\export fn entry() void { | ||
| 200 | \\ const a: Foo = undefined; | ||
| 201 | \\} | ||
| 202 | , | ||
| 203 | ".tmp_source.zig:3:5: error: duplicate error: 'Bar'", | ||
| 204 | ".tmp_source.zig:2:5: note: other error here"); | ||
| 205 | |||
| 4 | cases.add("cast negative integer literal to usize", | 206 | cases.add("cast negative integer literal to usize", |
| 5 | \\export fn entry() void { | 207 | \\export fn entry() void { |
| 6 | \\ const x = usize(-10); | 208 | \\ const x = usize(-10); |
| ... | @@ -112,12 +314,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { | ... | @@ -112,12 +314,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { |
| 112 | 314 | ||
| 113 | cases.add("wrong return type for main", | 315 | cases.add("wrong return type for main", |
| 114 | \\pub fn main() f32 { } | 316 | \\pub fn main() f32 { } |
| 115 | , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '%void'"); | 317 | , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"); |
| 116 | 318 | ||
| 117 | cases.add("double ?? on main return value", | 319 | cases.add("double ?? on main return value", |
| 118 | \\pub fn main() ??void { | 320 | \\pub fn main() ??void { |
| 119 | \\} | 321 | \\} |
| 120 | , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '%void'"); | 322 | , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"); |
| 121 | 323 | ||
| 122 | cases.add("bad identifier in function with struct defined inside function which references local const", | 324 | cases.add("bad identifier in function with struct defined inside function which references local const", |
| 123 | \\export fn entry() void { | 325 | \\export fn entry() void { |
| ... | @@ -1173,7 +1375,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { | ... | @@ -1173,7 +1375,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { |
| 1173 | \\export fn f() void { | 1375 | \\export fn f() void { |
| 1174 | \\ try something(); | 1376 | \\ try something(); |
| 1175 | \\} | 1377 | \\} |
| 1176 | \\fn something() %void { } | 1378 | \\fn something() error!void { } |
| 1177 | , | 1379 | , |
| 1178 | ".tmp_source.zig:2:5: error: expected type 'void', found 'error'"); | 1380 | ".tmp_source.zig:2:5: error: expected type 'void', found 'error'"); |
| 1179 | 1381 | ||
| ... | @@ -1264,7 +1466,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { | ... | @@ -1264,7 +1466,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { |
| 1264 | , ".tmp_source.zig:3:11: error: cannot assign to constant"); | 1466 | , ".tmp_source.zig:3:11: error: cannot assign to constant"); |
| 1265 | 1467 | ||
| 1266 | cases.add("main function with bogus args type", | 1468 | cases.add("main function with bogus args type", |
| 1267 | \\pub fn main(args: [][]bogus) %void {} | 1469 | \\pub fn main(args: [][]bogus) !void {} |
| 1268 | , ".tmp_source.zig:1:23: error: use of undeclared identifier 'bogus'"); | 1470 | , ".tmp_source.zig:1:23: error: use of undeclared identifier 'bogus'"); |
| 1269 | 1471 | ||
| 1270 | cases.add("for loop missing element param", | 1472 | cases.add("for loop missing element param", |
| ... | @@ -1396,7 +1598,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { | ... | @@ -1396,7 +1598,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { |
| 1396 | , ".tmp_source.zig:6:13: error: cannot assign to constant"); | 1598 | , ".tmp_source.zig:6:13: error: cannot assign to constant"); |
| 1397 | 1599 | ||
| 1398 | cases.add("return from defer expression", | 1600 | cases.add("return from defer expression", |
| 1399 | \\pub fn testTrickyDefer() %void { | 1601 | \\pub fn testTrickyDefer() !void { |
| 1400 | \\ defer canFail() catch {}; | 1602 | \\ defer canFail() catch {}; |
| 1401 | \\ | 1603 | \\ |
| 1402 | \\ defer try canFail(); | 1604 | \\ defer try canFail(); |
| ... | @@ -1404,7 +1606,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { | ... | @@ -1404,7 +1606,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { |
| 1404 | \\ const a = maybeInt() ?? return; | 1606 | \\ const a = maybeInt() ?? return; |
| 1405 | \\} | 1607 | \\} |
| 1406 | \\ | 1608 | \\ |
| 1407 | \\fn canFail() %void { } | 1609 | \\fn canFail() error!void { } |
| 1408 | \\ | 1610 | \\ |
| 1409 | \\pub fn maybeInt() ?i32 { | 1611 | \\pub fn maybeInt() ?i32 { |
| 1410 | \\ return 0; | 1612 | \\ return 0; |
| ... | @@ -1534,7 +1736,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { | ... | @@ -1534,7 +1736,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { |
| 1534 | \\export fn foo() void { | 1736 | \\export fn foo() void { |
| 1535 | \\ bar() catch unreachable; | 1737 | \\ bar() catch unreachable; |
| 1536 | \\} | 1738 | \\} |
| 1537 | \\fn bar() %i32 { return 0; } | 1739 | \\fn bar() error!i32 { return 0; } |
| 1538 | , ".tmp_source.zig:2:11: error: expression value is ignored"); | 1740 | , ".tmp_source.zig:2:11: error: expression value is ignored"); |
| 1539 | 1741 | ||
| 1540 | cases.add("ignored statement value", | 1742 | cases.add("ignored statement value", |
| ... | @@ -1565,7 +1767,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { | ... | @@ -1565,7 +1767,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { |
| 1565 | \\export fn foo() void { | 1767 | \\export fn foo() void { |
| 1566 | \\ defer bar(); | 1768 | \\ defer bar(); |
| 1567 | \\} | 1769 | \\} |
| 1568 | \\fn bar() %i32 { return 0; } | 1770 | \\fn bar() error!i32 { return 0; } |
| 1569 | , ".tmp_source.zig:2:14: error: expression value is ignored"); | 1771 | , ".tmp_source.zig:2:14: error: expression value is ignored"); |
| 1570 | 1772 | ||
| 1571 | cases.add("dereference an array", | 1773 | cases.add("dereference an array", |
| ... | @@ -1632,13 +1834,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { | ... | @@ -1632,13 +1834,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { |
| 1632 | , ".tmp_source.zig:2:21: error: expected pointer, found 'usize'"); | 1834 | , ".tmp_source.zig:2:21: error: expected pointer, found 'usize'"); |
| 1633 | 1835 | ||
| 1634 | cases.add("too many error values to cast to small integer", | 1836 | cases.add("too many error values to cast to small integer", |
| 1635 | \\error A; error B; error C; error D; error E; error F; error G; error H; | 1837 | \\const Error = error { A, B, C, D, E, F, G, H }; |
| 1636 | \\const u2 = @IntType(false, 2); | 1838 | \\fn foo(e: Error) u2 { |
| 1637 | \\fn foo(e: error) u2 { | ||
| 1638 | \\ return u2(e); | 1839 | \\ return u2(e); |
| 1639 | \\} | 1840 | \\} |
| 1640 | \\export fn entry() usize { return @sizeOf(@typeOf(foo)); } | 1841 | \\export fn entry() usize { return @sizeOf(@typeOf(foo)); } |
| 1641 | , ".tmp_source.zig:4:14: error: too many error values to fit in 'u2'"); | 1842 | , ".tmp_source.zig:3:14: error: too many error values to fit in 'u2'"); |
| 1642 | 1843 | ||
| 1643 | cases.add("asm at compile time", | 1844 | cases.add("asm at compile time", |
| 1644 | \\comptime { | 1845 | \\comptime { |
| ... | @@ -1821,9 +2022,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { | ... | @@ -1821,9 +2022,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { |
| 1821 | \\export fn foo() void { | 2022 | \\export fn foo() void { |
| 1822 | \\ while (bar()) {} | 2023 | \\ while (bar()) {} |
| 1823 | \\} | 2024 | \\} |
| 1824 | \\fn bar() %i32 { return 1; } | 2025 | \\fn bar() error!i32 { return 1; } |
| 1825 | , | 2026 | , |
| 1826 | ".tmp_source.zig:2:15: error: expected type 'bool', found '%i32'"); | 2027 | ".tmp_source.zig:2:15: error: expected type 'bool', found 'error!i32'"); |
| 1827 | 2028 | ||
| 1828 | cases.add("while expected nullable, got bool", | 2029 | cases.add("while expected nullable, got bool", |
| 1829 | \\export fn foo() void { | 2030 | \\export fn foo() void { |
| ... | @@ -1837,9 +2038,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { | ... | @@ -1837,9 +2038,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { |
| 1837 | \\export fn foo() void { | 2038 | \\export fn foo() void { |
| 1838 | \\ while (bar()) |x| {} | 2039 | \\ while (bar()) |x| {} |
| 1839 | \\} | 2040 | \\} |
| 1840 | \\fn bar() %i32 { return 1; } | 2041 | \\fn bar() error!i32 { return 1; } |
| 1841 | , | 2042 | , |
| 1842 | ".tmp_source.zig:2:15: error: expected nullable type, found '%i32'"); | 2043 | ".tmp_source.zig:2:15: error: expected nullable type, found 'error!i32'"); |
| 1843 | 2044 | ||
| 1844 | cases.add("while expected error union, got bool", | 2045 | cases.add("while expected error union, got bool", |
| 1845 | \\export fn foo() void { | 2046 | \\export fn foo() void { |
| ... | @@ -1983,7 +2184,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { | ... | @@ -1983,7 +2184,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { |
| 1983 | \\fn foo1(args: ...) void {} | 2184 | \\fn foo1(args: ...) void {} |
| 1984 | \\fn foo2(args: ...) void {} | 2185 | \\fn foo2(args: ...) void {} |
| 1985 | \\ | 2186 | \\ |
| 1986 | \\pub fn main() %void { | 2187 | \\pub fn main() !void { |
| 1987 | \\ foos[0](); | 2188 | \\ foos[0](); |
| 1988 | \\} | 2189 | \\} |
| 1989 | , | 2190 | , |
| ... | @@ -1995,7 +2196,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { | ... | @@ -1995,7 +2196,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { |
| 1995 | \\fn foo1(arg: var) void {} | 2196 | \\fn foo1(arg: var) void {} |
| 1996 | \\fn foo2(arg: var) void {} | 2197 | \\fn foo2(arg: var) void {} |
| 1997 | \\ | 2198 | \\ |
| 1998 | \\pub fn main() %void { | 2199 | \\pub fn main() !void { |
| 1999 | \\ foos[0](true); | 2200 | \\ foos[0](true); |
| 2000 | \\} | 2201 | \\} |
| 2001 | , | 2202 | , |
test/runtime_safety.zig+36-38| ... | @@ -5,7 +5,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -5,7 +5,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 5 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 5 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 6 | \\ @import("std").os.exit(126); | 6 | \\ @import("std").os.exit(126); |
| 7 | \\} | 7 | \\} |
| 8 | \\pub fn main() %void { | 8 | \\pub fn main() void { |
| 9 | \\ @panic("oh no"); | 9 | \\ @panic("oh no"); |
| 10 | \\} | 10 | \\} |
| 11 | ); | 11 | ); |
| ... | @@ -14,7 +14,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -14,7 +14,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 14 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 14 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 15 | \\ @import("std").os.exit(126); | 15 | \\ @import("std").os.exit(126); |
| 16 | \\} | 16 | \\} |
| 17 | \\pub fn main() %void { | 17 | \\pub fn main() void { |
| 18 | \\ const a = []i32{1, 2, 3, 4}; | 18 | \\ const a = []i32{1, 2, 3, 4}; |
| 19 | \\ baz(bar(a)); | 19 | \\ baz(bar(a)); |
| 20 | \\} | 20 | \\} |
| ... | @@ -28,8 +28,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -28,8 +28,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 28 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 28 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 29 | \\ @import("std").os.exit(126); | 29 | \\ @import("std").os.exit(126); |
| 30 | \\} | 30 | \\} |
| 31 | \\error Whatever; | 31 | \\pub fn main() !void { |
| 32 | \\pub fn main() %void { | ||
| 33 | \\ const x = add(65530, 10); | 32 | \\ const x = add(65530, 10); |
| 34 | \\ if (x == 0) return error.Whatever; | 33 | \\ if (x == 0) return error.Whatever; |
| 35 | \\} | 34 | \\} |
| ... | @@ -42,8 +41,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -42,8 +41,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 42 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 41 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 43 | \\ @import("std").os.exit(126); | 42 | \\ @import("std").os.exit(126); |
| 44 | \\} | 43 | \\} |
| 45 | \\error Whatever; | 44 | \\pub fn main() !void { |
| 46 | \\pub fn main() %void { | ||
| 47 | \\ const x = sub(10, 20); | 45 | \\ const x = sub(10, 20); |
| 48 | \\ if (x == 0) return error.Whatever; | 46 | \\ if (x == 0) return error.Whatever; |
| 49 | \\} | 47 | \\} |
| ... | @@ -56,8 +54,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -56,8 +54,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 56 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 54 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 57 | \\ @import("std").os.exit(126); | 55 | \\ @import("std").os.exit(126); |
| 58 | \\} | 56 | \\} |
| 59 | \\error Whatever; | 57 | \\pub fn main() !void { |
| 60 | \\pub fn main() %void { | ||
| 61 | \\ const x = mul(300, 6000); | 58 | \\ const x = mul(300, 6000); |
| 62 | \\ if (x == 0) return error.Whatever; | 59 | \\ if (x == 0) return error.Whatever; |
| 63 | \\} | 60 | \\} |
| ... | @@ -70,8 +67,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -70,8 +67,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 70 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 67 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 71 | \\ @import("std").os.exit(126); | 68 | \\ @import("std").os.exit(126); |
| 72 | \\} | 69 | \\} |
| 73 | \\error Whatever; | 70 | \\pub fn main() !void { |
| 74 | \\pub fn main() %void { | ||
| 75 | \\ const x = neg(-32768); | 71 | \\ const x = neg(-32768); |
| 76 | \\ if (x == 32767) return error.Whatever; | 72 | \\ if (x == 32767) return error.Whatever; |
| 77 | \\} | 73 | \\} |
| ... | @@ -84,8 +80,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -84,8 +80,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 84 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 80 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 85 | \\ @import("std").os.exit(126); | 81 | \\ @import("std").os.exit(126); |
| 86 | \\} | 82 | \\} |
| 87 | \\error Whatever; | 83 | \\pub fn main() !void { |
| 88 | \\pub fn main() %void { | ||
| 89 | \\ const x = div(-32768, -1); | 84 | \\ const x = div(-32768, -1); |
| 90 | \\ if (x == 32767) return error.Whatever; | 85 | \\ if (x == 32767) return error.Whatever; |
| 91 | \\} | 86 | \\} |
| ... | @@ -98,8 +93,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -98,8 +93,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 98 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 93 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 99 | \\ @import("std").os.exit(126); | 94 | \\ @import("std").os.exit(126); |
| 100 | \\} | 95 | \\} |
| 101 | \\error Whatever; | 96 | \\pub fn main() !void { |
| 102 | \\pub fn main() %void { | ||
| 103 | \\ const x = shl(-16385, 1); | 97 | \\ const x = shl(-16385, 1); |
| 104 | \\ if (x == 0) return error.Whatever; | 98 | \\ if (x == 0) return error.Whatever; |
| 105 | \\} | 99 | \\} |
| ... | @@ -112,8 +106,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -112,8 +106,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 112 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 106 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 113 | \\ @import("std").os.exit(126); | 107 | \\ @import("std").os.exit(126); |
| 114 | \\} | 108 | \\} |
| 115 | \\error Whatever; | 109 | \\pub fn main() !void { |
| 116 | \\pub fn main() %void { | ||
| 117 | \\ const x = shl(0b0010111111111111, 3); | 110 | \\ const x = shl(0b0010111111111111, 3); |
| 118 | \\ if (x == 0) return error.Whatever; | 111 | \\ if (x == 0) return error.Whatever; |
| 119 | \\} | 112 | \\} |
| ... | @@ -126,8 +119,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -126,8 +119,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 126 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 119 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 127 | \\ @import("std").os.exit(126); | 120 | \\ @import("std").os.exit(126); |
| 128 | \\} | 121 | \\} |
| 129 | \\error Whatever; | 122 | \\pub fn main() !void { |
| 130 | \\pub fn main() %void { | ||
| 131 | \\ const x = shr(-16385, 1); | 123 | \\ const x = shr(-16385, 1); |
| 132 | \\ if (x == 0) return error.Whatever; | 124 | \\ if (x == 0) return error.Whatever; |
| 133 | \\} | 125 | \\} |
| ... | @@ -140,8 +132,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -140,8 +132,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 140 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 132 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 141 | \\ @import("std").os.exit(126); | 133 | \\ @import("std").os.exit(126); |
| 142 | \\} | 134 | \\} |
| 143 | \\error Whatever; | 135 | \\pub fn main() !void { |
| 144 | \\pub fn main() %void { | ||
| 145 | \\ const x = shr(0b0010111111111111, 3); | 136 | \\ const x = shr(0b0010111111111111, 3); |
| 146 | \\ if (x == 0) return error.Whatever; | 137 | \\ if (x == 0) return error.Whatever; |
| 147 | \\} | 138 | \\} |
| ... | @@ -154,8 +145,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -154,8 +145,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 154 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 145 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 155 | \\ @import("std").os.exit(126); | 146 | \\ @import("std").os.exit(126); |
| 156 | \\} | 147 | \\} |
| 157 | \\error Whatever; | 148 | \\pub fn main() void { |
| 158 | \\pub fn main() %void { | ||
| 159 | \\ const x = div0(999, 0); | 149 | \\ const x = div0(999, 0); |
| 160 | \\} | 150 | \\} |
| 161 | \\fn div0(a: i32, b: i32) i32 { | 151 | \\fn div0(a: i32, b: i32) i32 { |
| ... | @@ -167,8 +157,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -167,8 +157,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 167 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 157 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 168 | \\ @import("std").os.exit(126); | 158 | \\ @import("std").os.exit(126); |
| 169 | \\} | 159 | \\} |
| 170 | \\error Whatever; | 160 | \\pub fn main() !void { |
| 171 | \\pub fn main() %void { | ||
| 172 | \\ const x = divExact(10, 3); | 161 | \\ const x = divExact(10, 3); |
| 173 | \\ if (x == 0) return error.Whatever; | 162 | \\ if (x == 0) return error.Whatever; |
| 174 | \\} | 163 | \\} |
| ... | @@ -181,8 +170,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -181,8 +170,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 181 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 170 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 182 | \\ @import("std").os.exit(126); | 171 | \\ @import("std").os.exit(126); |
| 183 | \\} | 172 | \\} |
| 184 | \\error Whatever; | 173 | \\pub fn main() !void { |
| 185 | \\pub fn main() %void { | ||
| 186 | \\ const x = widenSlice([]u8{1, 2, 3, 4, 5}); | 174 | \\ const x = widenSlice([]u8{1, 2, 3, 4, 5}); |
| 187 | \\ if (x.len == 0) return error.Whatever; | 175 | \\ if (x.len == 0) return error.Whatever; |
| 188 | \\} | 176 | \\} |
| ... | @@ -195,8 +183,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -195,8 +183,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 195 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 183 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 196 | \\ @import("std").os.exit(126); | 184 | \\ @import("std").os.exit(126); |
| 197 | \\} | 185 | \\} |
| 198 | \\error Whatever; | 186 | \\pub fn main() !void { |
| 199 | \\pub fn main() %void { | ||
| 200 | \\ const x = shorten_cast(200); | 187 | \\ const x = shorten_cast(200); |
| 201 | \\ if (x == 0) return error.Whatever; | 188 | \\ if (x == 0) return error.Whatever; |
| 202 | \\} | 189 | \\} |
| ... | @@ -209,8 +196,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -209,8 +196,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 209 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 196 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 210 | \\ @import("std").os.exit(126); | 197 | \\ @import("std").os.exit(126); |
| 211 | \\} | 198 | \\} |
| 212 | \\error Whatever; | 199 | \\pub fn main() !void { |
| 213 | \\pub fn main() %void { | ||
| 214 | \\ const x = unsigned_cast(-10); | 200 | \\ const x = unsigned_cast(-10); |
| 215 | \\ if (x == 0) return error.Whatever; | 201 | \\ if (x == 0) return error.Whatever; |
| 216 | \\} | 202 | \\} |
| ... | @@ -226,20 +212,19 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -226,20 +212,19 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 226 | \\ } | 212 | \\ } |
| 227 | \\ @import("std").os.exit(0); // test failed | 213 | \\ @import("std").os.exit(0); // test failed |
| 228 | \\} | 214 | \\} |
| 229 | \\error Whatever; | 215 | \\pub fn main() void { |
| 230 | \\pub fn main() %void { | ||
| 231 | \\ bar() catch unreachable; | 216 | \\ bar() catch unreachable; |
| 232 | \\} | 217 | \\} |
| 233 | \\fn bar() %void { | 218 | \\fn bar() !void { |
| 234 | \\ return error.Whatever; | 219 | \\ return error.Whatever; |
| 235 | \\} | 220 | \\} |
| 236 | ); | 221 | ); |
| 237 | 222 | ||
| 238 | cases.addRuntimeSafety("cast integer to error and no code matches", | 223 | cases.addRuntimeSafety("cast integer to global error and no code matches", |
| 239 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 224 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 240 | \\ @import("std").os.exit(126); | 225 | \\ @import("std").os.exit(126); |
| 241 | \\} | 226 | \\} |
| 242 | \\pub fn main() %void { | 227 | \\pub fn main() void { |
| 243 | \\ _ = bar(9999); | 228 | \\ _ = bar(9999); |
| 244 | \\} | 229 | \\} |
| 245 | \\fn bar(x: u32) error { | 230 | \\fn bar(x: u32) error { |
| ... | @@ -247,12 +232,25 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -247,12 +232,25 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 247 | \\} | 232 | \\} |
| 248 | ); | 233 | ); |
| 249 | 234 | ||
| 235 | cases.addRuntimeSafety("cast integer to non-global error set and no match", | ||
| 236 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | ||
| 237 | \\ @import("std").os.exit(126); | ||
| 238 | \\} | ||
| 239 | \\const Set1 = error{A, B}; | ||
| 240 | \\const Set2 = error{A, C}; | ||
| 241 | \\pub fn main() void { | ||
| 242 | \\ _ = foo(Set1.B); | ||
| 243 | \\} | ||
| 244 | \\fn foo(set1: Set1) Set2 { | ||
| 245 | \\ return Set2(set1); | ||
| 246 | \\} | ||
| 247 | ); | ||
| 248 | |||
| 250 | cases.addRuntimeSafety("@alignCast misaligned", | 249 | cases.addRuntimeSafety("@alignCast misaligned", |
| 251 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | 250 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { |
| 252 | \\ @import("std").os.exit(126); | 251 | \\ @import("std").os.exit(126); |
| 253 | \\} | 252 | \\} |
| 254 | \\error Wrong; | 253 | \\pub fn main() !void { |
| 255 | \\pub fn main() %void { | ||
| 256 | \\ var array align(4) = []u32{0x11111111, 0x11111111}; | 254 | \\ var array align(4) = []u32{0x11111111, 0x11111111}; |
| 257 | \\ const bytes = ([]u8)(array[0..]); | 255 | \\ const bytes = ([]u8)(array[0..]); |
| 258 | \\ if (foo(bytes) != 0x11111111) return error.Wrong; | 256 | \\ if (foo(bytes) != 0x11111111) return error.Wrong; |
| ... | @@ -274,7 +272,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { | ... | @@ -274,7 +272,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 274 | \\ int: u32, | 272 | \\ int: u32, |
| 275 | \\}; | 273 | \\}; |
| 276 | \\ | 274 | \\ |
| 277 | \\pub fn main() %void { | 275 | \\pub fn main() void { |
| 278 | \\ var f = Foo { .int = 42 }; | 276 | \\ var f = Foo { .int = 42 }; |
| 279 | \\ bar(&f); | 277 | \\ bar(&f); |
| 280 | \\} | 278 | \\} |
test/standalone/brace_expansion/build.zig+1-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | const Builder = @import("std").build.Builder; | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | ||
| 3 | pub fn build(b: &Builder) %void { | 3 | pub fn build(b: &Builder) void { |
| 4 | const main = b.addTest("main.zig"); | 4 | const main = b.addTest("main.zig"); |
| 5 | main.setBuildMode(b.standardReleaseOptions()); | 5 | main.setBuildMode(b.standardReleaseOptions()); |
| 6 | 6 |
test/standalone/brace_expansion/main.zig+14-8| ... | @@ -6,9 +6,6 @@ const assert = debug.assert; | ... | @@ -6,9 +6,6 @@ const assert = debug.assert; |
| 6 | const Buffer = std.Buffer; | 6 | const Buffer = std.Buffer; |
| 7 | const ArrayList = std.ArrayList; | 7 | const ArrayList = std.ArrayList; |
| 8 | 8 | ||
| 9 | error InvalidInput; | ||
| 10 | error OutOfMem; | ||
| 11 | |||
| 12 | const Token = union(enum) { | 9 | const Token = union(enum) { |
| 13 | Word: []const u8, | 10 | Word: []const u8, |
| 14 | OpenBrace, | 11 | OpenBrace, |
| ... | @@ -19,7 +16,7 @@ const Token = union(enum) { | ... | @@ -19,7 +16,7 @@ const Token = union(enum) { |
| 19 | 16 | ||
| 20 | var global_allocator: &mem.Allocator = undefined; | 17 | var global_allocator: &mem.Allocator = undefined; |
| 21 | 18 | ||
| 22 | fn tokenize(input:[] const u8) %ArrayList(Token) { | 19 | fn tokenize(input:[] const u8) !ArrayList(Token) { |
| 23 | const State = enum { | 20 | const State = enum { |
| 24 | Start, | 21 | Start, |
| 25 | Word, | 22 | Word, |
| ... | @@ -71,7 +68,12 @@ const Node = union(enum) { | ... | @@ -71,7 +68,12 @@ const Node = union(enum) { |
| 71 | Combine: []Node, | 68 | Combine: []Node, |
| 72 | }; | 69 | }; |
| 73 | 70 | ||
| 74 | fn parse(tokens: &const ArrayList(Token), token_index: &usize) %Node { | 71 | const ParseError = error { |
| 72 | InvalidInput, | ||
| 73 | OutOfMemory, | ||
| 74 | }; | ||
| 75 | |||
| 76 | fn parse(tokens: &const ArrayList(Token), token_index: &usize) ParseError!Node { | ||
| 75 | const first_token = tokens.items[*token_index]; | 77 | const first_token = tokens.items[*token_index]; |
| 76 | *token_index += 1; | 78 | *token_index += 1; |
| 77 | 79 | ||
| ... | @@ -107,7 +109,7 @@ fn parse(tokens: &const ArrayList(Token), token_index: &usize) %Node { | ... | @@ -107,7 +109,7 @@ fn parse(tokens: &const ArrayList(Token), token_index: &usize) %Node { |
| 107 | } | 109 | } |
| 108 | } | 110 | } |
| 109 | 111 | ||
| 110 | fn expandString(input: []const u8, output: &Buffer) %void { | 112 | fn expandString(input: []const u8, output: &Buffer) !void { |
| 111 | const tokens = try tokenize(input); | 113 | const tokens = try tokenize(input); |
| 112 | if (tokens.len == 1) { | 114 | if (tokens.len == 1) { |
| 113 | return output.resize(0); | 115 | return output.resize(0); |
| ... | @@ -135,7 +137,11 @@ fn expandString(input: []const u8, output: &Buffer) %void { | ... | @@ -135,7 +137,11 @@ fn expandString(input: []const u8, output: &Buffer) %void { |
| 135 | } | 137 | } |
| 136 | } | 138 | } |
| 137 | 139 | ||
| 138 | fn expandNode(node: &const Node, output: &ArrayList(Buffer)) %void { | 140 | const ExpandNodeError = error { |
| 141 | OutOfMemory, | ||
| 142 | }; | ||
| 143 | |||
| 144 | fn expandNode(node: &const Node, output: &ArrayList(Buffer)) ExpandNodeError!void { | ||
| 139 | assert(output.len == 0); | 145 | assert(output.len == 0); |
| 140 | switch (*node) { | 146 | switch (*node) { |
| 141 | Node.Scalar => |scalar| { | 147 | Node.Scalar => |scalar| { |
| ... | @@ -172,7 +178,7 @@ fn expandNode(node: &const Node, output: &ArrayList(Buffer)) %void { | ... | @@ -172,7 +178,7 @@ fn expandNode(node: &const Node, output: &ArrayList(Buffer)) %void { |
| 172 | } | 178 | } |
| 173 | } | 179 | } |
| 174 | 180 | ||
| 175 | pub fn main() %void { | 181 | pub fn main() !void { |
| 176 | var stdin_file = try io.getStdIn(); | 182 | var stdin_file = try io.getStdIn(); |
| 177 | var stdout_file = try io.getStdOut(); | 183 | var stdout_file = try io.getStdOut(); |
| 178 | 184 |
test/standalone/issue_339/build.zig+1-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | const Builder = @import("std").build.Builder; | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | ||
| 3 | pub fn build(b: &Builder) %void { | 3 | pub fn build(b: &Builder) void { |
| 4 | const obj = b.addObject("test", "test.zig"); | 4 | const obj = b.addObject("test", "test.zig"); |
| 5 | 5 | ||
| 6 | const test_step = b.step("test", "Test the program"); | 6 | const test_step = b.step("test", "Test the program"); |
test/standalone/issue_339/test.zig+1-1| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | const StackTrace = @import("builtin").StackTrace; | 1 | const StackTrace = @import("builtin").StackTrace; |
| 2 | pub fn panic(msg: []const u8, stack_trace: ?&StackTrace) noreturn { @breakpoint(); while (true) {} } | 2 | pub fn panic(msg: []const u8, stack_trace: ?&StackTrace) noreturn { @breakpoint(); while (true) {} } |
| 3 | 3 | ||
| 4 | fn bar() %void {} | 4 | fn bar() error!void {} |
| 5 | 5 | ||
| 6 | export fn foo() void { | 6 | export fn foo() void { |
| 7 | bar() catch unreachable; | 7 | bar() catch unreachable; |
test/standalone/pkg_import/build.zig+1-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | const Builder = @import("std").build.Builder; | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | ||
| 3 | pub fn build(b: &Builder) %void { | 3 | pub fn build(b: &Builder) void { |
| 4 | const exe = b.addExecutable("test", "test.zig"); | 4 | const exe = b.addExecutable("test", "test.zig"); |
| 5 | exe.addPackagePath("my_pkg", "pkg.zig"); | 5 | exe.addPackagePath("my_pkg", "pkg.zig"); |
| 6 | 6 |
test/standalone/pkg_import/test.zig+1-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | const my_pkg = @import("my_pkg"); | 1 | const my_pkg = @import("my_pkg"); |
| 2 | const assert = @import("std").debug.assert; | 2 | const assert = @import("std").debug.assert; |
| 3 | 3 | ||
| 4 | pub fn main() %void { | 4 | pub fn main() void { |
| 5 | assert(my_pkg.add(10, 20) == 30); | 5 | assert(my_pkg.add(10, 20) == 30); |
| 6 | } | 6 | } |
test/standalone/use_alias/build.zig+1-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | const Builder = @import("std").build.Builder; | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | ||
| 3 | pub fn build(b: &Builder) %void { | 3 | pub fn build(b: &Builder) void { |
| 4 | b.addCIncludePath("."); | 4 | b.addCIncludePath("."); |
| 5 | 5 | ||
| 6 | const main = b.addTest("main.zig"); | 6 | const main = b.addTest("main.zig"); |
test/tests.zig+5-8| ... | @@ -45,9 +45,6 @@ const test_targets = []TestTarget { | ... | @@ -45,9 +45,6 @@ const test_targets = []TestTarget { |
| 45 | }, | 45 | }, |
| 46 | }; | 46 | }; |
| 47 | 47 | ||
| 48 | error TestFailed; | ||
| 49 | error CompilationIncorrectlySucceeded; | ||
| 50 | |||
| 51 | const max_stdout_size = 1 * 1024 * 1024; // 1 MB | 48 | const max_stdout_size = 1 * 1024 * 1024; // 1 MB |
| 52 | 49 | ||
| 53 | pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step { | 50 | pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step { |
| ... | @@ -248,7 +245,7 @@ pub const CompareOutputContext = struct { | ... | @@ -248,7 +245,7 @@ pub const CompareOutputContext = struct { |
| 248 | return ptr; | 245 | return ptr; |
| 249 | } | 246 | } |
| 250 | 247 | ||
| 251 | fn make(step: &build.Step) %void { | 248 | fn make(step: &build.Step) !void { |
| 252 | const self = @fieldParentPtr(RunCompareOutputStep, "step", step); | 249 | const self = @fieldParentPtr(RunCompareOutputStep, "step", step); |
| 253 | const b = self.context.b; | 250 | const b = self.context.b; |
| 254 | 251 | ||
| ... | @@ -337,7 +334,7 @@ pub const CompareOutputContext = struct { | ... | @@ -337,7 +334,7 @@ pub const CompareOutputContext = struct { |
| 337 | return ptr; | 334 | return ptr; |
| 338 | } | 335 | } |
| 339 | 336 | ||
| 340 | fn make(step: &build.Step) %void { | 337 | fn make(step: &build.Step) !void { |
| 341 | const self = @fieldParentPtr(RuntimeSafetyRunStep, "step", step); | 338 | const self = @fieldParentPtr(RuntimeSafetyRunStep, "step", step); |
| 342 | const b = self.context.b; | 339 | const b = self.context.b; |
| 343 | 340 | ||
| ... | @@ -563,7 +560,7 @@ pub const CompileErrorContext = struct { | ... | @@ -563,7 +560,7 @@ pub const CompileErrorContext = struct { |
| 563 | return ptr; | 560 | return ptr; |
| 564 | } | 561 | } |
| 565 | 562 | ||
| 566 | fn make(step: &build.Step) %void { | 563 | fn make(step: &build.Step) !void { |
| 567 | const self = @fieldParentPtr(CompileCmpOutputStep, "step", step); | 564 | const self = @fieldParentPtr(CompileCmpOutputStep, "step", step); |
| 568 | const b = self.context.b; | 565 | const b = self.context.b; |
| 569 | 566 | ||
| ... | @@ -847,7 +844,7 @@ pub const TranslateCContext = struct { | ... | @@ -847,7 +844,7 @@ pub const TranslateCContext = struct { |
| 847 | return ptr; | 844 | return ptr; |
| 848 | } | 845 | } |
| 849 | 846 | ||
| 850 | fn make(step: &build.Step) %void { | 847 | fn make(step: &build.Step) !void { |
| 851 | const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step); | 848 | const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step); |
| 852 | const b = self.context.b; | 849 | const b = self.context.b; |
| 853 | 850 | ||
| ... | @@ -1045,7 +1042,7 @@ pub const GenHContext = struct { | ... | @@ -1045,7 +1042,7 @@ pub const GenHContext = struct { |
| 1045 | return ptr; | 1042 | return ptr; |
| 1046 | } | 1043 | } |
| 1047 | 1044 | ||
| 1048 | fn make(step: &build.Step) %void { | 1045 | fn make(step: &build.Step) !void { |
| 1049 | const self = @fieldParentPtr(GenHCmpOutputStep, "step", step); | 1046 | const self = @fieldParentPtr(GenHCmpOutputStep, "step", step); |
| 1050 | const b = self.context.b; | 1047 | const b = self.context.b; |
| 1051 | 1048 |