authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-14 18:27:59-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-14 18:27:59-04:00
log32dd98b19fe3cc384df32704dac0ff3e377dbe0c
tree2eddf3618d80313bdd24c25bd589bd474f3d82fc
parentef7f69d14a017c6c2065e4a376bb8e1f05ace04b
parentf0697c28f80d64c544302aea576e41ebc443b41c

Merge remote-tracking branch 'origin/master' into llvm7


93 files changed, 5383 insertions(+), 2150 deletions(-)

CMakeLists.txt+3
......@@ -464,6 +464,7 @@ set(ZIG_STD_FILES
464464 "math/atan.zig"
465465 "math/atan2.zig"
466466 "math/atanh.zig"
467 "math/big/int.zig"
467468 "math/cbrt.zig"
468469 "math/ceil.zig"
469470 "math/complex/abs.zig"
......@@ -555,6 +556,7 @@ set(ZIG_STD_FILES
555556 "special/compiler_rt/aulldiv.zig"
556557 "special/compiler_rt/aullrem.zig"
557558 "special/compiler_rt/comparetf2.zig"
559 "special/compiler_rt/divti3.zig"
558560 "special/compiler_rt/fixuint.zig"
559561 "special/compiler_rt/fixunsdfdi.zig"
560562 "special/compiler_rt/fixunsdfsi.zig"
......@@ -565,6 +567,7 @@ set(ZIG_STD_FILES
565567 "special/compiler_rt/fixunstfdi.zig"
566568 "special/compiler_rt/fixunstfsi.zig"
567569 "special/compiler_rt/fixunstfti.zig"
570 "special/compiler_rt/muloti4.zig"
568571 "special/compiler_rt/index.zig"
569572 "special/compiler_rt/udivmod.zig"
570573 "special/compiler_rt/udivmoddi4.zig"
README.md+12-12
......@@ -55,18 +55,18 @@ that counts as "freestanding" for the purposes of this table.
5555|i386 | OK | planned | OK | planned | planned |
5656|x86_64 | OK | OK | OK | OK | planned |
5757|arm | OK | planned | planned | N/A | planned |
58|aarch64 | OK | planned | planned | planned | planned |
59|bpf | OK | planned | planned | N/A | planned |
60|hexagon | OK | planned | planned | N/A | planned |
61|mips | OK | planned | planned | N/A | planned |
62|powerpc | OK | planned | planned | N/A | planned |
63|r600 | OK | planned | planned | N/A | planned |
64|amdgcn | OK | planned | planned | N/A | planned |
65|sparc | OK | planned | planned | N/A | planned |
66|s390x | OK | planned | planned | N/A | planned |
67|thumb | OK | planned | planned | N/A | planned |
68|spir | OK | planned | planned | N/A | planned |
69|lanai | OK | planned | planned | N/A | planned |
58|aarch64 | OK | planned | N/A | planned | planned |
59|bpf | OK | planned | N/A | N/A | planned |
60|hexagon | OK | planned | N/A | N/A | planned |
61|mips | OK | planned | N/A | N/A | planned |
62|powerpc | OK | planned | N/A | N/A | planned |
63|r600 | OK | planned | N/A | N/A | planned |
64|amdgcn | OK | planned | N/A | N/A | planned |
65|sparc | OK | planned | N/A | N/A | planned |
66|s390x | OK | planned | N/A | N/A | planned |
67|thumb | OK | planned | N/A | N/A | planned |
68|spir | OK | planned | N/A | N/A | planned |
69|lanai | OK | planned | N/A | N/A | planned |
7070
7171## Community
7272
build.zig+5-4
......@@ -63,6 +63,7 @@ pub fn build(b: *Builder) !void {
6363 exe.addObjectFile(lib);
6464 }
6565 } else {
66 addCppLib(b, exe, cmake_binary_dir, "embedded_lld_wasm");
6667 addCppLib(b, exe, cmake_binary_dir, "embedded_lld_elf");
6768 addCppLib(b, exe, cmake_binary_dir, "embedded_lld_coff");
6869 addCppLib(b, exe, cmake_binary_dir, "embedded_lld_lib");
......@@ -74,7 +75,7 @@ pub fn build(b: *Builder) !void {
7475 cxx_compiler,
7576 "-print-file-name=libstdc++.a",
7677 });
77 const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();
78 const libstdcxx_path = mem.split(libstdcxx_path_padded, "\r\n").next().?;
7879 if (mem.eql(u8, libstdcxx_path, "libstdc++.a")) {
7980 warn(
8081 \\Unable to determine path to libstdc++.a
......@@ -101,11 +102,11 @@ pub fn build(b: *Builder) !void {
101102
102103 b.default_step.dependOn(&exe.step);
103104
104 const skip_self_hosted = b.option(bool, "skip-self-hosted", "Main test suite skips building self hosted compiler") ?? false;
105 const skip_self_hosted = b.option(bool, "skip-self-hosted", "Main test suite skips building self hosted compiler") orelse false;
105106 if (!skip_self_hosted) {
106107 test_step.dependOn(&exe.step);
107108 }
108 const verbose_link_exe = b.option(bool, "verbose-link", "Print link command for self hosted compiler") ?? false;
109 const verbose_link_exe = b.option(bool, "verbose-link", "Print link command for self hosted compiler") orelse false;
109110 exe.setVerboseLink(verbose_link_exe);
110111
111112 b.installArtifact(exe);
......@@ -113,7 +114,7 @@ pub fn build(b: *Builder) !void {
113114 installCHeaders(b, c_header_files);
114115
115116 const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter");
116 const with_lldb = b.option(bool, "with-lldb", "Run tests in LLDB to get a backtrace if one fails") ?? false;
117 const with_lldb = b.option(bool, "with-lldb", "Run tests in LLDB to get a backtrace if one fails") orelse false;
117118
118119 test_step.dependOn(docs_step);
119120
doc/codegen.md+4-4
......@@ -6,7 +6,7 @@ Every type has a "handle". If a type is a simple primitive type such as i32 or
66f64, the handle is "by value", meaning that we pass around the value itself when
77we refer to a value of that type.
88
9If a type is a container, error union, maybe type, slice, or array, then its
9If a type is a container, error union, optional type, slice, or array, then its
1010handle is a pointer, and everywhere we refer to a value of this type we refer to
1111a pointer.
1212
......@@ -19,7 +19,7 @@ Error union types are represented as:
1919 payload: T,
2020 }
2121
22Maybe types are represented as:
22Optional types are represented as:
2323
2424 struct {
2525 payload: T,
......@@ -28,6 +28,6 @@ Maybe types are represented as:
2828
2929## Data Optimizations
3030
31Maybe pointer types are special: the 0x0 pointer value is used to represent a
32null pointer. Thus, instead of the struct above, maybe pointer types are
31Optional pointer types are special: the 0x0 pointer value is used to represent a
32null pointer. Thus, instead of the struct above, optional pointer types are
3333represented as a `usize` in codegen and the handle is by value.
doc/docgen.zig+28-11
......@@ -25,13 +25,13 @@ pub fn main() !void {
2525
2626 if (!args_it.skip()) @panic("expected self arg");
2727
28 const zig_exe = try (args_it.next(allocator) ?? @panic("expected zig exe arg"));
28 const zig_exe = try (args_it.next(allocator) orelse @panic("expected zig exe arg"));
2929 defer allocator.free(zig_exe);
3030
31 const in_file_name = try (args_it.next(allocator) ?? @panic("expected input arg"));
31 const in_file_name = try (args_it.next(allocator) orelse @panic("expected input arg"));
3232 defer allocator.free(in_file_name);
3333
34 const out_file_name = try (args_it.next(allocator) ?? @panic("expected output arg"));
34 const out_file_name = try (args_it.next(allocator) orelse @panic("expected output arg"));
3535 defer allocator.free(out_file_name);
3636
3737 var in_file = try os.File.openRead(allocator, in_file_name);
......@@ -51,14 +51,8 @@ pub fn main() !void {
5151 var toc = try genToc(allocator, &tokenizer);
5252
5353 try os.makePath(allocator, tmp_dir_name);
54 defer {
55 // TODO issue #709
56 // disabled to pass CI tests, but obviously we want to implement this
57 // and then remove this workaround
58 if (builtin.os != builtin.Os.windows) {
59 os.deleteTree(allocator, tmp_dir_name) catch {};
60 }
61 }
54 defer os.deleteTree(allocator, tmp_dir_name) catch {};
55
6256 try genHtml(allocator, &tokenizer, &toc, &buffered_out_stream.stream, zig_exe);
6357 try buffered_out_stream.flush();
6458}
......@@ -300,6 +294,7 @@ const Link = struct {
300294const Node = union(enum) {
301295 Content: []const u8,
302296 Nav,
297 Builtin,
303298 HeaderOpen: HeaderOpen,
304299 SeeAlso: []const SeeAlsoItem,
305300 Code: Code,
......@@ -356,6 +351,9 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
356351 _ = try eatToken(tokenizer, Token.Id.BracketClose);
357352
358353 try nodes.append(Node.Nav);
354 } else if (mem.eql(u8, tag_name, "builtin")) {
355 _ = try eatToken(tokenizer, Token.Id.BracketClose);
356 try nodes.append(Node.Builtin);
359357 } else if (mem.eql(u8, tag_name, "header_open")) {
360358 _ = try eatToken(tokenizer, Token.Id.Separator);
361359 const content_token = try eatToken(tokenizer, Token.Id.TagContent);
......@@ -690,6 +688,9 @@ fn termColor(allocator: *mem.Allocator, input: []const u8) ![]u8 {
690688
691689fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var, zig_exe: []const u8) !void {
692690 var code_progress_index: usize = 0;
691
692 const builtin_code = try escapeHtml(allocator, try getBuiltinCode(allocator, zig_exe));
693
693694 for (toc.nodes) |node| {
694695 switch (node) {
695696 Node.Content => |data| {
......@@ -704,6 +705,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
704705 Node.Nav => {
705706 try out.write(toc.toc);
706707 },
708 Node.Builtin => {
709 try out.print("<pre><code class=\"zig\">{}</code></pre>", builtin_code);
710 },
707711 Node.HeaderOpen => |info| {
708712 try out.print("<h{} id=\"{}\">{}</h{}>\n", info.n, info.url, info.name, info.n);
709713 },
......@@ -954,6 +958,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
954958 var build_args = std.ArrayList([]const u8).init(allocator);
955959 defer build_args.deinit();
956960
961 const name_plus_h_ext = try std.fmt.allocPrint(allocator, "{}.h", code.name);
962 const output_h_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_h_ext);
963
957964 try build_args.appendSlice([][]const u8{
958965 zig_exe,
959966 "build-obj",
......@@ -962,6 +969,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
962969 "on",
963970 "--output",
964971 tmp_obj_file_name,
972 "--output-h",
973 output_h_file_name,
965974 });
966975
967976 if (!code.is_inline) {
......@@ -1060,3 +1069,11 @@ fn exec(allocator: *mem.Allocator, args: []const []const u8) !os.ChildProcess.Ex
10601069 }
10611070 return result;
10621071}
1072
1073fn getBuiltinCode(allocator: *mem.Allocator, zig_exe: []const u8) ![]const u8 {
1074 const result = try exec(allocator, []const []const u8{
1075 zig_exe,
1076 "builtin",
1077 });
1078 return result.stdout;
1079}
doc/langref.html.in+609-511
......@@ -156,18 +156,18 @@ pub fn main() void {
156156 true or false,
157157 !true);
158158
159 // nullable
160 var nullable_value: ?[]const u8 = null;
161 assert(nullable_value == null);
159 // optional
160 var optional_value: ?[]const u8 = null;
161 assert(optional_value == null);
162162
163 warn("\nnullable 1\ntype: {}\nvalue: {}\n",
164 @typeName(@typeOf(nullable_value)), nullable_value);
163 warn("\noptional 1\ntype: {}\nvalue: {}\n",
164 @typeName(@typeOf(optional_value)), optional_value);
165165
166 nullable_value = "hi";
167 assert(nullable_value != null);
166 optional_value = "hi";
167 assert(optional_value != null);
168168
169 warn("\nnullable 2\ntype: {}\nvalue: {}\n",
170 @typeName(@typeOf(nullable_value)), nullable_value);
169 warn("\noptional 2\ntype: {}\nvalue: {}\n",
170 @typeName(@typeOf(optional_value)), optional_value);
171171
172172 // error union
173173 var number_or_error: error!i32 = error.ArgNotFound;
......@@ -428,7 +428,7 @@ pub fn main() void {
428428 </tr>
429429 <tr>
430430 <td><code>null</code></td>
431 <td>used to set a nullable type to <code>null</code></td>
431 <td>used to set an optional type to <code>null</code></td>
432432 </tr>
433433 <tr>
434434 <td><code>undefined</code></td>
......@@ -440,7 +440,7 @@ pub fn main() void {
440440 </tr>
441441 </table>
442442 </div>
443 {#see_also|Nullables|this#}
443 {#see_also|Optionals|this#}
444444 {#header_close#}
445445 {#header_open|String Literals#}
446446 {#code_begin|test#}
......@@ -590,6 +590,7 @@ test "initialization" {
590590 x = 1;
591591}
592592 {#code_end#}
593 {#header_open|undefined#}
593594 <p>Use <code>undefined</code> to leave variables uninitialized:</p>
594595 {#code_begin|test#}
595596const assert = @import("std").debug.assert;
......@@ -602,6 +603,7 @@ test "init with undefined" {
602603 {#code_end#}
603604 {#header_close#}
604605 {#header_close#}
606 {#header_close#}
605607 {#header_open|Integers#}
606608 {#header_open|Integer Literals#}
607609 {#code_begin|syntax#}
......@@ -985,10 +987,10 @@ a ^= b</code></pre></td>
985987 </td>
986988 </tr>
987989 <tr>
988 <td><pre><code class="zig">a ?? b</code></pre></td>
990 <td><pre><code class="zig">a orelse b</code></pre></td>
989991 <td>
990992 <ul>
991 <li>{#link|Nullables#}</li>
993 <li>{#link|Optionals#}</li>
992994 </ul>
993995 </td>
994996 <td>If <code>a</code> is <code>null</code>,
......@@ -998,24 +1000,24 @@ a ^= b</code></pre></td>
9981000 </td>
9991001 <td>
10001002 <pre><code class="zig">const value: ?u32 = null;
1001const unwrapped = value ?? 1234;
1003const unwrapped = value orelse 1234;
10021004unwrapped == 1234</code></pre>
10031005 </td>
10041006 </tr>
10051007 <tr>
1006 <td><pre><code class="zig">??a</code></pre></td>
1008 <td><pre><code class="zig">a.?</code></pre></td>
10071009 <td>
10081010 <ul>
1009 <li>{#link|Nullables#}</li>
1011 <li>{#link|Optionals#}</li>
10101012 </ul>
10111013 </td>
10121014 <td>
10131015 Equivalent to:
1014 <pre><code class="zig">a ?? unreachable</code></pre>
1016 <pre><code class="zig">a orelse unreachable</code></pre>
10151017 </td>
10161018 <td>
10171019 <pre><code class="zig">const value: ?u32 = 5678;
1018??value == 5678</code></pre>
1020value.? == 5678</code></pre>
10191021 </td>
10201022 </tr>
10211023 <tr>
......@@ -1103,7 +1105,7 @@ unwrapped == 1234</code></pre>
11031105 <td><pre><code class="zig">a == null<code></pre></td>
11041106 <td>
11051107 <ul>
1106 <li>{#link|Nullables#}</li>
1108 <li>{#link|Optionals#}</li>
11071109 </ul>
11081110 </td>
11091111 <td>
......@@ -1261,15 +1263,31 @@ const ptr = &amp;x;
12611263x.* == 1234</code></pre>
12621264 </td>
12631265 </tr>
1266 <tr>
1267 <td><pre><code class="zig">a || b<code></pre></td>
1268 <td>
1269 <ul>
1270 <li>{#link|Error Set Type#}</li>
1271 </ul>
1272 </td>
1273 <td>
1274 {#link|Merging Error Sets#}
1275 </td>
1276 <td>
1277 <pre><code class="zig">const A = error{One};
1278const B = error{Two};
1279(A || B) == error{One, Two}</code></pre>
1280 </td>
1281 </tr>
12641282 </table>
12651283 </div>
12661284 {#header_close#}
12671285 {#header_open|Precedence#}
12681286 <pre><code>x() x[] x.y
12691287a!b
1270!x -x -%x ~x &amp;x ?x ??x
1271x{} x.*
1272! * / % ** *%
1288!x -x -%x ~x &amp;x ?x
1289x{} x.* x.?
1290! * / % ** *% ||
12731291+ - ++ +% -%
12741292&lt;&lt; &gt;&gt;
12751293&amp;
......@@ -1278,7 +1296,7 @@ x{} x.*
12781296== != &lt; &gt; &lt;= &gt;=
12791297and
12801298or
1281?? catch
1299orelse catch
12821300= *= /= %= += -= &lt;&lt;= &gt;&gt;= &amp;= ^= |=</code></pre>
12831301 {#header_close#}
12841302 {#header_close#}
......@@ -1483,17 +1501,17 @@ test "volatile" {
14831501 assert(@typeOf(mmio_ptr) == *volatile u8);
14841502}
14851503
1486test "nullable pointers" {
1487 // Pointers cannot be null. If you want a null pointer, use the nullable
1488 // prefix `?` to make the pointer type nullable.
1504test "optional pointers" {
1505 // Pointers cannot be null. If you want a null pointer, use the optional
1506 // prefix `?` to make the pointer type optional.
14891507 var ptr: ?*i32 = null;
14901508
14911509 var x: i32 = 1;
14921510 ptr = &x;
14931511
1494 assert((??ptr).* == 1);
1512 assert(ptr.?.* == 1);
14951513
1496 // Nullable pointers are the same size as normal pointers, because pointer
1514 // Optional pointers are the same size as normal pointers, because pointer
14971515 // value 0 is used as the null value.
14981516 assert(@sizeOf(?*i32) == @sizeOf(*i32));
14991517}
......@@ -1832,7 +1850,7 @@ test "linked list" {
18321850 .last = &node,
18331851 .len = 1,
18341852 };
1835 assert((??list2.first).data == 1234);
1853 assert(list2.first.?.data == 1234);
18361854}
18371855 {#code_end#}
18381856 {#see_also|comptime|@fieldParentPtr#}
......@@ -2270,7 +2288,7 @@ fn rangeHasNumber(begin: usize, end: usize, number: usize) bool {
22702288}
22712289
22722290test "while null capture" {
2273 // Just like if expressions, while loops can take a nullable as the
2291 // Just like if expressions, while loops can take an optional as the
22742292 // condition and capture the payload. When null is encountered the loop
22752293 // exits.
22762294 var sum1: u32 = 0;
......@@ -2280,7 +2298,7 @@ test "while null capture" {
22802298 }
22812299 assert(sum1 == 3);
22822300
2283 // The else branch is allowed on nullable iteration. In this case, it will
2301 // The else branch is allowed on optional iteration. In this case, it will
22842302 // be executed on the first null value encountered.
22852303 var sum2: u32 = 0;
22862304 numbers_left = 3;
......@@ -2340,7 +2358,7 @@ fn typeNameLength(comptime T: type) usize {
23402358 return @typeName(T).len;
23412359}
23422360 {#code_end#}
2343 {#see_also|if|Nullables|Errors|comptime|unreachable#}
2361 {#see_also|if|Optionals|Errors|comptime|unreachable#}
23442362 {#header_close#}
23452363 {#header_open|for#}
23462364 {#code_begin|test|for#}
......@@ -2400,7 +2418,7 @@ test "for else" {
24002418 if (value == null) {
24012419 break 9;
24022420 } else {
2403 sum += ??value;
2421 sum += value.?;
24042422 }
24052423 } else blk: {
24062424 assert(sum == 7);
......@@ -2461,7 +2479,7 @@ test "if boolean" {
24612479 assert(result == 47);
24622480}
24632481
2464test "if nullable" {
2482test "if optional" {
24652483 // If expressions test for null.
24662484
24672485 const a: ?u32 = 0;
......@@ -2544,7 +2562,7 @@ test "if error union" {
25442562 }
25452563}
25462564 {#code_end#}
2547 {#see_also|Nullables|Errors#}
2565 {#see_also|Optionals|Errors#}
25482566 {#header_close#}
25492567 {#header_open|defer#}
25502568 {#code_begin|test|defer#}
......@@ -2983,6 +3001,7 @@ test "parse u64" {
29833001 <li>You know with complete certainty it will not return an error, so want to unconditionally unwrap it.</li>
29843002 <li>You want to take a different action for each possible error.</li>
29853003 </ul>
3004 {#header_open|catch#}
29863005 <p>If you want to provide a default value, you can use the <code>catch</code> binary operator:</p>
29873006 {#code_begin|syntax#}
29883007fn doAThing(str: []u8) void {
......@@ -2995,6 +3014,8 @@ fn doAThing(str: []u8) void {
29953014 a default value of 13. The type of the right hand side of the binary <code>catch</code> operator must
29963015 match the unwrapped error union type, or be of type <code>noreturn</code>.
29973016 </p>
3017 {#header_close#}
3018 {#header_open|try#}
29983019 <p>Let's say you wanted to return the error if you got one, otherwise continue with the
29993020 function logic:</p>
30003021 {#code_begin|syntax#}
......@@ -3017,6 +3038,7 @@ fn doAThing(str: []u8) !void {
30173038 from the current function with the same error. Otherwise, the expression results in
30183039 the unwrapped value.
30193040 </p>
3041 {#header_close#}
30203042 <p>
30213043 Maybe you know with complete certainty that an expression will never be an error.
30223044 In this case you can do this:
......@@ -3031,7 +3053,7 @@ fn doAThing(str: []u8) !void {
30313053 </p>
30323054 <p>
30333055 Finally, you may want to take a different action for every situation. For that, we combine
3034 the <code>if</code> and <code>switch</code> expression:
3056 the {#link|if#} and {#link|switch#} expression:
30353057 </p>
30363058 {#code_begin|syntax#}
30373059fn doAThing(str: []u8) void {
......@@ -3046,9 +3068,10 @@ fn doAThing(str: []u8) void {
30463068 }
30473069}
30483070 {#code_end#}
3071 {#header_open|errdefer#}
30493072 <p>
30503073 The other component to error handling is defer statements.
3051 In addition to an unconditional <code>defer</code>, Zig has <code>errdefer</code>,
3074 In addition to an unconditional {#link|defer#}, Zig has <code>errdefer</code>,
30523075 which evaluates the deferred expression on block exit path if and only if
30533076 the function returned with an error from the block.
30543077 </p>
......@@ -3062,7 +3085,7 @@ fn createFoo(param: i32) !Foo {
30623085 // but we want to return it if the function succeeds.
30633086 errdefer deallocateFoo(foo);
30643087
3065 const tmp_buf = allocateTmpBuffer() ?? return error.OutOfMemory;
3088 const tmp_buf = allocateTmpBuffer() orelse return error.OutOfMemory;
30663089 // tmp_buf is truly a temporary resource, and we for sure want to clean it up
30673090 // before this block leaves scope
30683091 defer deallocateTmpBuffer(tmp_buf);
......@@ -3079,6 +3102,7 @@ fn createFoo(param: i32) !Foo {
30793102 the verbosity and cognitive overhead of trying to make sure every exit path
30803103 is covered. The deallocation code is always directly following the allocation code.
30813104 </p>
3105 {#header_close#}
30823106 <p>
30833107 A couple of other tidbits about error handling:
30843108 </p>
......@@ -3117,7 +3141,50 @@ test "error union" {
31173141 comptime assert(@typeOf(foo).ErrorSet == error);
31183142}
31193143 {#code_end#}
3120 <p>TODO the <code>||</code> operator for error sets</p>
3144 {#header_open|Merging Error Sets#}
3145 <p>
3146 Use the <code>||</code> operator to merge two error sets together. The resulting
3147 error set contains the errors of both error sets. Doc comments from the left-hand
3148 side override doc comments from the right-hand side. In this example, the doc
3149 comments for <code>C.PathNotFound</code> is <code>A doc comment</code>.
3150 </p>
3151 <p>
3152 This is especially useful for functions which return different error sets depending
3153 on {#link|comptime#} branches. For example, the Zig standard library uses
3154 <code>LinuxFileOpenError || WindowsFileOpenError</code> for the error set of opening
3155 files.
3156 </p>
3157 {#code_begin|test#}
3158const A = error{
3159 NotDir,
3160
3161 /// A doc comment
3162 PathNotFound,
3163};
3164const B = error{
3165 OutOfMemory,
3166
3167 /// B doc comment
3168 PathNotFound,
3169};
3170
3171const C = A || B;
3172
3173fn foo() C!void {
3174 return error.NotDir;
3175}
3176
3177test "merge error sets" {
3178 if (foo()) {
3179 @panic("unexpected");
3180 } else |err| switch (err) {
3181 error.OutOfMemory => @panic("unexpected"),
3182 error.PathNotFound => @panic("unexpected"),
3183 error.NotDir => {},
3184 }
3185}
3186 {#code_end#}
3187 {#header_close#}
31213188 {#header_open|Inferred Error Sets#}
31223189 <p>
31233190 Because many functions in Zig return a possible error, Zig supports inferring the error set.
......@@ -3164,27 +3231,194 @@ test "inferred error set" {
31643231 {#header_close#}
31653232 {#header_close#}
31663233 {#header_open|Error Return Traces#}
3167 <p>TODO</p>
3234 <p>
3235 Error Return Traces show all the points in the code that an error was returned to the calling function. This makes it practical to use {#link|try#} everywhere and then still be able to know what happened if an error ends up bubbling all the way out of your application.
3236 </p>
3237 {#code_begin|exe_err#}
3238pub fn main() !void {
3239 try foo(12);
3240}
3241
3242fn foo(x: i32) !void {
3243 if (x >= 5) {
3244 try bar();
3245 } else {
3246 try bang2();
3247 }
3248}
3249
3250fn bar() !void {
3251 if (baz()) {
3252 try quux();
3253 } else |err| switch (err) {
3254 error.FileNotFound => try hello(),
3255 else => try another(),
3256 }
3257}
3258
3259fn baz() !void {
3260 try bang1();
3261}
3262
3263fn quux() !void {
3264 try bang2();
3265}
3266
3267fn hello() !void {
3268 try bang2();
3269}
3270
3271fn another() !void {
3272 try bang1();
3273}
3274
3275fn bang1() !void {
3276 return error.FileNotFound;
3277}
3278
3279fn bang2() !void {
3280 return error.PermissionDenied;
3281}
3282 {#code_end#}
3283 <p>
3284 Look closely at this example. This is no stack trace.
3285 </p>
3286 <p>
3287 You can see that the final error bubbled up was <code>PermissionDenied</code>,
3288 but the original error that started this whole thing was <code>FileNotFound</code>. In the <code>bar</code> function, the code handles the original error code,
3289 and then returns another one, from the switch statement. Error Return Traces make this clear, whereas a stack trace would look like this:
3290 </p>
3291 {#code_begin|exe_err#}
3292pub fn main() void {
3293 foo(12);
3294}
3295
3296fn foo(x: i32) void {
3297 if (x >= 5) {
3298 bar();
3299 } else {
3300 bang2();
3301 }
3302}
3303
3304fn bar() void {
3305 if (baz()) {
3306 quux();
3307 } else {
3308 hello();
3309 }
3310}
3311
3312fn baz() bool {
3313 return bang1();
3314}
3315
3316fn quux() void {
3317 bang2();
3318}
3319
3320fn hello() void {
3321 bang2();
3322}
3323
3324fn bang1() bool {
3325 return false;
3326}
3327
3328fn bang2() void {
3329 @panic("PermissionDenied");
3330}
3331 {#code_end#}
3332 <p>
3333 Here, the stack trace does not explain how the control
3334 flow in <code>bar</code> got to the <code>hello()</code> call.
3335 One would have to open a debugger or further instrument the application
3336 in order to find out. The error return trace, on the other hand,
3337 shows exactly how the error bubbled up.
3338 </p>
3339 <p>
3340 This debugging feature makes it easier to iterate quickly on code that
3341 robustly handles all error conditions. This means that Zig developers
3342 will naturally find themselves writing correct, robust code in order
3343 to increase their development pace.
3344 </p>
3345 <p>
3346 Error Return Traces are enabled by default in {#link|Debug#} and {#link|ReleaseSafe#} builds and disabled by default in {#link|ReleaseFast#} and {#link|ReleaseSmall#} builds.
3347 </p>
3348 <p>
3349 There are a few ways to activate this error return tracing feature:
3350 </p>
3351 <ul>
3352 <li>Return an error from main</li>
3353 <li>An error makes its way to <code>catch unreachable</code> and you have not overridden the default panic handler</li>
3354 <li>Use {#link|errorReturnTrace#} to access the current return trace. You can use <code>std.debug.dumpStackTrace</code> to print it. This function returns comptime-known {#link|null#} when building without error return tracing support.</li>
3355 </ul>
3356 {#header_open|Implementation Details#}
3357 <p>
3358 To analyze performance cost, there are two cases:
3359 </p>
3360 <ul>
3361 <li>when no errors are returned</li>
3362 <li>when returning errors</li>
3363 </ul>
3364 <p>
3365 For the case when no errors are returned, the cost is a single memory write operation, only in the first non-failable function in the call graph that calls a failable function, i.e. when a function returning <code>void</code> calls a function returning <code>error</code>.
3366 This is to initialize this struct in the stack memory:
3367 </p>
3368 {#code_begin|syntax#}
3369pub const StackTrace = struct {
3370 index: usize,
3371 instruction_addresses: [N]usize,
3372};
3373 {#code_end#}
3374 <p>
3375 Here, N is the maximum function call depth as determined by call graph analysis. Recursion is ignored and counts for 2.
3376 </p>
3377 <p>
3378 A pointer to <code>StackTrace</code> is passed as a secret parameter to every function that can return an error, but it's always the first parameter, so it can likely sit in a register and stay there.
3379 </p>
3380 <p>
3381 That's it for the path when no errors occur. It's practically free in terms of performance.
3382 </p>
3383 <p>
3384 When generating the code for a function that returns an error, just before the <code>return</code> statement (only for the <code>return</code> statements that return errors), Zig generates a call to this function:
3385 </p>
3386 {#code_begin|syntax#}
3387// marked as "no-inline" in LLVM IR
3388fn __zig_return_error(stack_trace: *StackTrace) void {
3389 stack_trace.instruction_addresses[stack_trace.index] = @returnAddress();
3390 stack_trace.index = (stack_trace.index + 1) % N;
3391}
3392 {#code_end#}
3393 <p>
3394 The cost is 2 math operations plus some memory reads and writes. The memory accessed is constrained and should remain cached for the duration of the error return bubbling.
3395 </p>
3396 <p>
3397 As for code size cost, 1 function call before a return statement is no big deal. Even so,
3398 I have <a href="https://github.com/ziglang/zig/issues/690">a plan</a> to make the call to
3399 <code>__zig_return_error</code> a tail call, which brings the code size cost down to actually zero. What is a return statement in code without error return tracing can become a jump instruction in code with error return tracing.
3400 </p>
31683401 {#header_close#}
31693402 {#header_close#}
3170 {#header_open|Nullables#}
3403 {#header_close#}
3404 {#header_open|Optionals#}
31713405 <p>
31723406 One area that Zig provides safety without compromising efficiency or
3173 readability is with the nullable type.
3407 readability is with the optional type.
31743408 </p>
31753409 <p>
3176 The question mark symbolizes the nullable type. You can convert a type to a nullable
3410 The question mark symbolizes the optional type. You can convert a type to an optional
31773411 type by putting a question mark in front of it, like this:
31783412 </p>
31793413 {#code_begin|syntax#}
31803414// normal integer
31813415const normal_int: i32 = 1234;
31823416
3183// nullable integer
3184const nullable_int: ?i32 = 5678;
3417// optional integer
3418const optional_int: ?i32 = 5678;
31853419 {#code_end#}
31863420 <p>
3187 Now the variable <code>nullable_int</code> could be an <code>i32</code>, or <code>null</code>.
3421 Now the variable <code>optional_int</code> could be an <code>i32</code>, or <code>null</code>.
31883422 </p>
31893423 <p>
31903424 Instead of integers, let's talk about pointers. Null references are the source of many runtime
......@@ -3193,8 +3427,8 @@ const nullable_int: ?i32 = 5678;
31933427 </p>
31943428 <p>Zig does not have them.</p>
31953429 <p>
3196 Instead, you can use a nullable pointer. This secretly compiles down to a normal pointer,
3197 since we know we can use 0 as the null value for the nullable type. But the compiler
3430 Instead, you can use an optional pointer. This secretly compiles down to a normal pointer,
3431 since we know we can use 0 as the null value for the optional type. But the compiler
31983432 can check your work and make sure you don't assign null to something that can't be null.
31993433 </p>
32003434 <p>
......@@ -3219,14 +3453,14 @@ struct Foo *do_a_thing(void) {
32193453extern fn malloc(size: size_t) ?*u8;
32203454
32213455fn doAThing() ?*Foo {
3222 const ptr = malloc(1234) ?? return null;
3456 const ptr = malloc(1234) orelse return null;
32233457 // ...
32243458}
32253459 {#code_end#}
32263460 <p>
32273461 Here, Zig is at least as convenient, if not more, than C. And, the type of "ptr"
3228 is <code>*u8</code> <em>not</em> <code>?*u8</code>. The <code>??</code> operator
3229 unwrapped the nullable type and therefore <code>ptr</code> is guaranteed to be non-null everywhere
3462 is <code>*u8</code> <em>not</em> <code>?*u8</code>. The <code>orelse</code> keyword
3463 unwrapped the optional type and therefore <code>ptr</code> is guaranteed to be non-null everywhere
32303464 it is used in the function.
32313465 </p>
32323466 <p>
......@@ -3245,10 +3479,10 @@ fn doAThing() ?*Foo {
32453479 In Zig you can accomplish the same thing:
32463480 </p>
32473481 {#code_begin|syntax#}
3248fn doAThing(nullable_foo: ?*Foo) void {
3482fn doAThing(optional_foo: ?*Foo) void {
32493483 // do some stuff
32503484
3251 if (nullable_foo) |foo| {
3485 if (optional_foo) |foo| {
32523486 doSomethingWithFoo(foo);
32533487 }
32543488
......@@ -3257,7 +3491,7 @@ fn doAThing(nullable_foo: ?*Foo) void {
32573491 {#code_end#}
32583492 <p>
32593493 Once again, the notable thing here is that inside the if block,
3260 <code>foo</code> is no longer a nullable pointer, it is a pointer, which
3494 <code>foo</code> is no longer an optional pointer, it is a pointer, which
32613495 cannot be null.
32623496 </p>
32633497 <p>
......@@ -3267,22 +3501,31 @@ fn doAThing(nullable_foo: ?*Foo) void {
32673501 The optimizer can sometimes make better decisions knowing that pointer arguments
32683502 cannot be null.
32693503 </p>
3270 {#header_open|Nullable Type#}
3271 <p>A nullable is created by putting <code>?</code> in front of a type. You can use compile-time
3272 reflection to access the child type of a nullable:</p>
3504 {#header_open|Optional Type#}
3505 <p>An optional is created by putting <code>?</code> in front of a type. You can use compile-time
3506 reflection to access the child type of an optional:</p>
32733507 {#code_begin|test#}
32743508const assert = @import("std").debug.assert;
32753509
3276test "nullable type" {
3277 // Declare a nullable and implicitly cast from null:
3510test "optional type" {
3511 // Declare an optional and implicitly cast from null:
32783512 var foo: ?i32 = null;
32793513
3280 // Implicitly cast from child type of a nullable
3514 // Implicitly cast from child type of an optional
32813515 foo = 1234;
32823516
3283 // Use compile-time reflection to access the child type of the nullable:
3517 // Use compile-time reflection to access the child type of the optional:
32843518 comptime assert(@typeOf(foo).Child == i32);
32853519}
3520 {#code_end#}
3521 {#header_close#}
3522 {#header_open|null#}
3523 <p>
3524 Just like {#link|undefined#}, <code>null</code> has its own type, and the only way to use it is to
3525 cast it to a different type:
3526 </p>
3527 {#code_begin|syntax#}
3528const optional_value: ?i32 = null;
32863529 {#code_end#}
32873530 {#header_close#}
32883531 {#header_close#}
......@@ -3845,9 +4088,6 @@ pub fn printValue(self: *OutStream, value: var) !void {
38454088 return self.printInt(T, value);
38464089 } else if (@isFloat(T)) {
38474090 return self.printFloat(T, value);
3848 } else if (@canImplicitCast([]const u8, value)) {
3849 const casted_value = ([]const u8)(value);
3850 return self.write(casted_value);
38514091 } else {
38524092 @compileError("Unable to print type '" ++ @typeName(T) ++ "'");
38534093 }
......@@ -3911,6 +4151,277 @@ pub fn main() void {
39114151 <p>TODO: @fence()</p>
39124152 <p>TODO: @atomic rmw</p>
39134153 <p>TODO: builtin atomic memory ordering enum</p>
4154 {#header_close#}
4155 {#header_open|Coroutines#}
4156 <p>
4157 A coroutine is a generalization of a function.
4158 </p>
4159 <p>
4160 When you call a function, it creates a stack frame,
4161 and then the function runs until it reaches a return
4162 statement, and then the stack frame is destroyed.
4163 At the callsite, the next line of code does not run
4164 until the function returns.
4165 </p>
4166 <p>
4167 A coroutine is like a function, but it can be suspended
4168 and resumed any number of times, and then it must be
4169 explicitly destroyed. When a coroutine suspends, it
4170 returns to the resumer.
4171 </p>
4172 {#header_open|Minimal Coroutine Example#}
4173 <p>
4174 Declare a coroutine with the <code>async</code> keyword.
4175 The expression in angle brackets must evaluate to a struct
4176 which has these fields:
4177 </p>
4178 <ul>
4179 <li><code>allocFn: fn (self: *Allocator, byte_count: usize, alignment: u29) Error![]u8</code> - where <code>Error</code> can be any error set.</li>
4180 <li><code>freeFn: fn (self: *Allocator, old_mem: []u8) void</code></li>
4181 </ul>
4182 <p>
4183 You may notice that this corresponds to the <code>std.mem.Allocator</code> interface.
4184 This makes it convenient to integrate with existing allocators. Note, however,
4185 that the language feature does not depend on the standard library, and any struct which
4186 has these fields is allowed.
4187 </p>
4188 <p>
4189 Omitting the angle bracket expression when defining an async function makes
4190 the function generic. Zig will infer the allocator type when the async function is called.
4191 </p>
4192 <p>
4193 Call a coroutine with the <code>async</code> keyword. Here, the expression in angle brackets
4194 is a pointer to the allocator struct that the coroutine expects.
4195 </p>
4196 <p>
4197 The result of an async function call is a <code>promise->T</code> type, where <code>T</code>
4198 is the return type of the async function. Once a promise has been created, it must be
4199 consumed, either with <code>cancel</code> or <code>await</code>:
4200 </p>
4201 <p>
4202 Async functions start executing when created, so in the following example, the entire
4203 async function completes before it is canceled:
4204 </p>
4205 {#code_begin|test#}
4206const std = @import("std");
4207const assert = std.debug.assert;
4208
4209var x: i32 = 1;
4210
4211test "create a coroutine and cancel it" {
4212 const p = try async<std.debug.global_allocator> simpleAsyncFn();
4213 comptime assert(@typeOf(p) == promise->void);
4214 cancel p;
4215 assert(x == 2);
4216}
4217async<*std.mem.Allocator> fn simpleAsyncFn() void {
4218 x += 1;
4219}
4220 {#code_end#}
4221 {#header_close#}
4222 {#header_open|Suspend and Resume#}
4223 <p>
4224 At any point, an async function may suspend itself. This causes control flow to
4225 return to the caller or resumer. The following code demonstrates where control flow
4226 goes:
4227 </p>
4228 {#code_begin|test#}
4229const std = @import("std");
4230const assert = std.debug.assert;
4231
4232test "coroutine suspend, resume, cancel" {
4233 seq('a');
4234 const p = try async<std.debug.global_allocator> testAsyncSeq();
4235 seq('c');
4236 resume p;
4237 seq('f');
4238 cancel p;
4239 seq('g');
4240
4241 assert(std.mem.eql(u8, points, "abcdefg"));
4242}
4243async fn testAsyncSeq() void {
4244 defer seq('e');
4245
4246 seq('b');
4247 suspend;
4248 seq('d');
4249}
4250var points = []u8{0} ** "abcdefg".len;
4251var index: usize = 0;
4252
4253fn seq(c: u8) void {
4254 points[index] = c;
4255 index += 1;
4256}
4257 {#code_end#}
4258 <p>
4259 When an async function suspends itself, it must be sure that it will be
4260 resumed or canceled somehow, for example by registering its promise handle
4261 in an event loop. Use a suspend capture block to gain access to the
4262 promise:
4263 </p>
4264 {#code_begin|test#}
4265const std = @import("std");
4266const assert = std.debug.assert;
4267
4268test "coroutine suspend with block" {
4269 const p = try async<std.debug.global_allocator> testSuspendBlock();
4270 std.debug.assert(!result);
4271 resume a_promise;
4272 std.debug.assert(result);
4273 cancel p;
4274}
4275
4276var a_promise: promise = undefined;
4277var result = false;
4278async fn testSuspendBlock() void {
4279 suspend |p| {
4280 comptime assert(@typeOf(p) == promise->void);
4281 a_promise = p;
4282 }
4283 result = true;
4284}
4285 {#code_end#}
4286 <p>
4287 Every suspend point in an async function represents a point at which the coroutine
4288 could be destroyed. If that happens, <code>defer</code> expressions that are in
4289 scope are run, as well as <code>errdefer</code> expressions.
4290 </p>
4291 <p>
4292 {#link|Await#} counts as a suspend point.
4293 </p>
4294 {#header_open|Breaking from Suspend Blocks#}
4295 <p>
4296 Suspend blocks support labeled break, just like {#link|while#} and {#link|for#}.
4297 </p>
4298 <p>
4299 Upon entering a <code>suspend</code> block, the coroutine is already considered
4300 suspended, and can be resumed. For example, if you started another kernel thread,
4301 and had that thread call <code>resume</code> on the promise handle provided by the
4302 <code>suspend</code> block, the new thread would begin executing after the suspend
4303 block, while the old thread continued executing the suspend block.
4304 </p>
4305 <p>
4306 However, if you use labeled <code>break</code> on the suspend block, the coroutine
4307 never returns to its resumer and continues executing.
4308 </p>
4309 {#code_begin|test#}
4310const std = @import("std");
4311const assert = std.debug.assert;
4312
4313test "break from suspend" {
4314 var buf: [500]u8 = undefined;
4315 var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
4316 var my_result: i32 = 1;
4317 const p = try async<a> testBreakFromSuspend(&my_result);
4318 cancel p;
4319 std.debug.assert(my_result == 2);
4320}
4321async fn testBreakFromSuspend(my_result: *i32) void {
4322 s: suspend |p| {
4323 break :s;
4324 }
4325 my_result.* += 1;
4326 suspend;
4327 my_result.* += 1;
4328}
4329 {#code_end#}
4330 {#header_close#}
4331 {#header_close#}
4332 {#header_open|Await#}
4333 <p>
4334 The <code>await</code> keyword is used to coordinate with an async function's
4335 <code>return</code> statement.
4336 </p>
4337 <p>
4338 <code>await</code> is valid only in an <code>async</code> function, and it takes
4339 as an operand a promise handle.
4340 If the async function associated with the promise handle has already returned,
4341 then <code>await</code> destroys the target async function, and gives the return value.
4342 Otherwise, <code>await</code> suspends the current async function, registering its
4343 promise handle with the target coroutine. It becomes the target coroutine's responsibility
4344 to have ensured that it will be resumed or destroyed. When the target coroutine reaches
4345 its return statement, it gives the return value to the awaiter, destroys itself, and then
4346 resumes the awaiter.
4347 </p>
4348 <p>
4349 A promise handle must be consumed exactly once after it is created, either by <code>cancel</code> or <code>await</code>.
4350 </p>
4351 <p>
4352 <code>await</code> counts as a suspend point, and therefore at every <code>await</code>,
4353 a coroutine can be potentially destroyed, which would run <code>defer</code> and <code>errdefer</code> expressions.
4354 </p>
4355 {#code_begin|test#}
4356const std = @import("std");
4357const assert = std.debug.assert;
4358
4359var a_promise: promise = undefined;
4360var final_result: i32 = 0;
4361
4362test "coroutine await" {
4363 seq('a');
4364 const p = async<std.debug.global_allocator> amain() catch unreachable;
4365 seq('f');
4366 resume a_promise;
4367 seq('i');
4368 assert(final_result == 1234);
4369 assert(std.mem.eql(u8, seq_points, "abcdefghi"));
4370}
4371async fn amain() void {
4372 seq('b');
4373 const p = async another() catch unreachable;
4374 seq('e');
4375 final_result = await p;
4376 seq('h');
4377}
4378async fn another() i32 {
4379 seq('c');
4380 suspend |p| {
4381 seq('d');
4382 a_promise = p;
4383 }
4384 seq('g');
4385 return 1234;
4386}
4387
4388var seq_points = []u8{0} ** "abcdefghi".len;
4389var seq_index: usize = 0;
4390
4391fn seq(c: u8) void {
4392 seq_points[seq_index] = c;
4393 seq_index += 1;
4394}
4395 {#code_end#}
4396 <p>
4397 In general, <code>suspend</code> is lower level than <code>await</code>. Most application
4398 code will use only <code>async</code> and <code>await</code>, but event loop
4399 implementations will make use of <code>suspend</code> internally.
4400 </p>
4401 {#header_close#}
4402 {#header_open|Open Issues#}
4403 <p>
4404 There are a few issues with coroutines that are considered unresolved. Best be aware of them,
4405 as the situation is likely to change before 1.0.0:
4406 </p>
4407 <ul>
4408 <li>Async functions have optimizations disabled - even in release modes - due to an
4409 <a href="https://github.com/ziglang/zig/issues/802">LLVM bug</a>.
4410 </li>
4411 <li>
4412 There are some situations where we can know statically that there will not be
4413 memory allocation failure, but Zig still forces us to handle it.
4414 TODO file an issue for this and link it here.
4415 </li>
4416 <li>
4417 Zig does not take advantage of LLVM's allocation elision optimization for
4418 coroutines. It crashed LLVM when I tried to do it the first time. This is
4419 related to the other 2 bullet points here. See
4420 <a href="https://github.com/ziglang/zig/issues/802">#802</a>.
4421 </li>
4422 </ul>
4423 {#header_close#}
4424
39144425 {#header_close#}
39154426 {#header_open|Builtin Functions#}
39164427 <p>
......@@ -4102,12 +4613,6 @@ comptime {
41024613 </p>
41034614 {#see_also|Import from C Header File|@cImport|@cDefine|@cInclude#}
41044615 {#header_close#}
4105 {#header_open|@canImplicitCast#}
4106 <pre><code class="zig">@canImplicitCast(comptime T: type, value) bool</code></pre>
4107 <p>
4108 Returns whether a value can be implicitly casted to a given type.
4109 </p>
4110 {#header_close#}
41114616 {#header_open|@clz#}
41124617 <pre><code class="zig">@clz(x: T) U</code></pre>
41134618 <p>
......@@ -4897,7 +5402,7 @@ pub const TypeId = enum {
48975402 ComptimeInt,
48985403 Undefined,
48995404 Null,
4900 Nullable,
5405 Optional,
49015406 ErrorUnion,
49025407 Error,
49035408 Enum,
......@@ -4931,7 +5436,7 @@ pub const TypeInfo = union(TypeId) {
49315436 ComptimeInt: void,
49325437 Undefined: void,
49335438 Null: void,
4934 Nullable: Nullable,
5439 Optional: Optional,
49355440 ErrorUnion: ErrorUnion,
49365441 ErrorSet: ErrorSet,
49375442 Enum: Enum,
......@@ -4984,7 +5489,7 @@ pub const TypeInfo = union(TypeId) {
49845489 defs: []Definition,
49855490 };
49865491
4987 pub const Nullable = struct {
5492 pub const Optional = struct {
49885493 child: type,
49895494 };
49905495
......@@ -5105,12 +5610,13 @@ pub const TypeInfo = union(TypeId) {
51055610 {#header_close#}
51065611 {#header_open|Build Mode#}
51075612 <p>
5108 Zig has three build modes:
5613 Zig has four build modes:
51095614 </p>
51105615 <ul>
51115616 <li>{#link|Debug#} (default)</li>
51125617 <li>{#link|ReleaseFast#}</li>
51135618 <li>{#link|ReleaseSafe#}</li>
5619 <li>{#link|ReleaseSmall#}</li>
51145620 </ul>
51155621 <p>
51165622 To add standard build options to a <code>build.zig</code> file:
......@@ -5127,14 +5633,16 @@ pub fn build(b: &Builder) void {
51275633 <p>
51285634 This causes these options to be available:
51295635 </p>
5130 <pre><code class="shell"> -Drelease-safe=(bool) optimizations on and safety on
5131 -Drelease-fast=(bool) optimizations on and safety off</code></pre>
5636 <pre><code class="shell"> -Drelease-safe=[bool] optimizations on and safety on
5637 -Drelease-fast=[bool] optimizations on and safety off
5638 -Drelease-small=[bool] size optimizations on and safety off</code></pre>
51325639 {#header_open|Debug#}
51335640 <pre><code class="shell">$ zig build-exe example.zig</code></pre>
51345641 <ul>
51355642 <li>Fast compilation speed</li>
51365643 <li>Safety checks enabled</li>
51375644 <li>Slow runtime performance</li>
5645 <li>Large binary size</li>
51385646 </ul>
51395647 {#header_close#}
51405648 {#header_open|ReleaseFast#}
......@@ -5143,6 +5651,7 @@ pub fn build(b: &Builder) void {
51435651 <li>Fast runtime performance</li>
51445652 <li>Safety checks disabled</li>
51455653 <li>Slow compilation speed</li>
5654 <li>Large binary size</li>
51465655 </ul>
51475656 {#header_close#}
51485657 {#header_open|ReleaseSafe#}
......@@ -5151,9 +5660,19 @@ pub fn build(b: &Builder) void {
51515660 <li>Medium runtime performance</li>
51525661 <li>Safety checks enabled</li>
51535662 <li>Slow compilation speed</li>
5663 <li>Large binary size</li>
5664 </ul>
5665 {#header_close#}
5666 {#header_open|ReleaseSmall#}
5667 <pre><code class="shell">$ zig build-exe example.zig --release-small</code></pre>
5668 <ul>
5669 <li>Medium runtime performance</li>
5670 <li>Safety checks disabled</li>
5671 <li>Slow compilation speed</li>
5672 <li>Small binary size</li>
51545673 </ul>
5155 {#see_also|Compile Variables|Zig Build System|Undefined Behavior#}
51565674 {#header_close#}
5675 {#see_also|Compile Variables|Zig Build System|Undefined Behavior#}
51575676 {#header_close#}
51585677 {#header_open|Undefined Behavior#}
51595678 <p>
......@@ -5161,7 +5680,7 @@ pub fn build(b: &Builder) void {
51615680 detected at compile-time, Zig emits an error. Most undefined behavior that
51625681 cannot be detected at compile-time can be detected at runtime. In these cases,
51635682 Zig has safety checks. Safety checks can be disabled on a per-block basis
5164 with <code>@setRuntimeSafety</code>. The {#link|ReleaseFast#}
5683 with {#link|setRuntimeSafety#}. The {#link|ReleaseFast#}
51655684 build mode disables all safety checks in order to facilitate optimizations.
51665685 </p>
51675686 <p>
......@@ -5375,8 +5894,8 @@ comptime {
53755894 <p>At compile-time:</p>
53765895 {#code_begin|test_err|unable to unwrap null#}
53775896comptime {
5378 const nullable_number: ?i32 = null;
5379 const number = ??nullable_number;
5897 const optional_number: ?i32 = null;
5898 const number = optional_number.?;
53805899}
53815900 {#code_end#}
53825901 <p>At runtime crashes with the message <code>attempt to unwrap null</code> and a stack trace.</p>
......@@ -5385,9 +5904,9 @@ comptime {
53855904 {#code_begin|exe|test#}
53865905const warn = @import("std").debug.warn;
53875906pub fn main() void {
5388 const nullable_number: ?i32 = null;
5907 const optional_number: ?i32 = null;
53895908
5390 if (nullable_number) |number| {
5909 if (optional_number) |number| {
53915910 warn("got number: {}\n", number);
53925911 } else {
53935912 warn("it's null\n");
......@@ -5474,425 +5993,7 @@ const separator = if (builtin.os == builtin.Os.windows) '\\' else '/';
54745993 <p>
54755994 Example of what is imported with <code>@import("builtin")</code>:
54765995 </p>
5477 {#code_begin|syntax#}
5478pub const StackTrace = struct {
5479 index: usize,
5480 instruction_addresses: []usize,
5481};
5482
5483pub const Os = enum {
5484 freestanding,
5485 ananas,
5486 cloudabi,
5487 dragonfly,
5488 freebsd,
5489 fuchsia,
5490 ios,
5491 kfreebsd,
5492 linux,
5493 lv2,
5494 macosx,
5495 netbsd,
5496 openbsd,
5497 solaris,
5498 windows,
5499 haiku,
5500 minix,
5501 rtems,
5502 nacl,
5503 cnk,
5504 aix,
5505 cuda,
5506 nvcl,
5507 amdhsa,
5508 ps4,
5509 elfiamcu,
5510 tvos,
5511 watchos,
5512 mesa3d,
5513 contiki,
5514 amdpal,
5515 zen,
5516};
5517
5518pub const Arch = enum {
5519 armv8_3a,
5520 armv8_2a,
5521 armv8_1a,
5522 armv8,
5523 armv8r,
5524 armv8m_baseline,
5525 armv8m_mainline,
5526 armv7,
5527 armv7em,
5528 armv7m,
5529 armv7s,
5530 armv7k,
5531 armv7ve,
5532 armv6,
5533 armv6m,
5534 armv6k,
5535 armv6t2,
5536 armv5,
5537 armv5te,
5538 armv4t,
5539 armebv8_3a,
5540 armebv8_2a,
5541 armebv8_1a,
5542 armebv8,
5543 armebv8r,
5544 armebv8m_baseline,
5545 armebv8m_mainline,
5546 armebv7,
5547 armebv7em,
5548 armebv7m,
5549 armebv7s,
5550 armebv7k,
5551 armebv7ve,
5552 armebv6,
5553 armebv6m,
5554 armebv6k,
5555 armebv6t2,
5556 armebv5,
5557 armebv5te,
5558 armebv4t,
5559 aarch64,
5560 aarch64_be,
5561 arc,
5562 avr,
5563 bpfel,
5564 bpfeb,
5565 hexagon,
5566 mips,
5567 mipsel,
5568 mips64,
5569 mips64el,
5570 msp430,
5571 nios2,
5572 powerpc,
5573 powerpc64,
5574 powerpc64le,
5575 r600,
5576 amdgcn,
5577 riscv32,
5578 riscv64,
5579 sparc,
5580 sparcv9,
5581 sparcel,
5582 s390x,
5583 tce,
5584 tcele,
5585 thumb,
5586 thumbeb,
5587 i386,
5588 x86_64,
5589 xcore,
5590 nvptx,
5591 nvptx64,
5592 le32,
5593 le64,
5594 amdil,
5595 amdil64,
5596 hsail,
5597 hsail64,
5598 spir,
5599 spir64,
5600 kalimbav3,
5601 kalimbav4,
5602 kalimbav5,
5603 shave,
5604 lanai,
5605 wasm32,
5606 wasm64,
5607 renderscript32,
5608 renderscript64,
5609};
5610
5611pub const Environ = enum {
5612 unknown,
5613 gnu,
5614 gnuabin32,
5615 gnuabi64,
5616 gnueabi,
5617 gnueabihf,
5618 gnux32,
5619 code16,
5620 eabi,
5621 eabihf,
5622 android,
5623 musl,
5624 musleabi,
5625 musleabihf,
5626 msvc,
5627 itanium,
5628 cygnus,
5629 amdopencl,
5630 coreclr,
5631 opencl,
5632 simulator,
5633};
5634
5635pub const ObjectFormat = enum {
5636 unknown,
5637 coff,
5638 elf,
5639 macho,
5640 wasm,
5641};
5642
5643pub const GlobalLinkage = enum {
5644 Internal,
5645 Strong,
5646 Weak,
5647 LinkOnce,
5648};
5649
5650pub const AtomicOrder = enum {
5651 Unordered,
5652 Monotonic,
5653 Acquire,
5654 Release,
5655 AcqRel,
5656 SeqCst,
5657};
5658
5659pub const AtomicRmwOp = enum {
5660 Xchg,
5661 Add,
5662 Sub,
5663 And,
5664 Nand,
5665 Or,
5666 Xor,
5667 Max,
5668 Min,
5669};
5670
5671pub const Mode = enum {
5672 Debug,
5673 ReleaseSafe,
5674 ReleaseFast,
5675 ReleaseSmall,
5676};
5677
5678pub const TypeId = enum {
5679 Type,
5680 Void,
5681 Bool,
5682 NoReturn,
5683 Int,
5684 Float,
5685 Pointer,
5686 Array,
5687 Struct,
5688 ComptimeFloat,
5689 ComptimeInt,
5690 Undefined,
5691 Null,
5692 Nullable,
5693 ErrorUnion,
5694 ErrorSet,
5695 Enum,
5696 Union,
5697 Fn,
5698 Namespace,
5699 Block,
5700 BoundFn,
5701 ArgTuple,
5702 Opaque,
5703 Promise,
5704};
5705
5706pub const TypeInfo = union(TypeId) {
5707 Type: void,
5708 Void: void,
5709 Bool: void,
5710 NoReturn: void,
5711 Int: Int,
5712 Float: Float,
5713 Pointer: Pointer,
5714 Array: Array,
5715 Struct: Struct,
5716 ComptimeFloat: void,
5717 ComptimeInt: void,
5718 Undefined: void,
5719 Null: void,
5720 Nullable: Nullable,
5721 ErrorUnion: ErrorUnion,
5722 ErrorSet: ErrorSet,
5723 Enum: Enum,
5724 Union: Union,
5725 Fn: Fn,
5726 Namespace: void,
5727 Block: void,
5728 BoundFn: Fn,
5729 ArgTuple: void,
5730 Opaque: void,
5731 Promise: Promise,
5732
5733
5734 pub const Int = struct {
5735 is_signed: bool,
5736 bits: u8,
5737 };
5738
5739 pub const Float = struct {
5740 bits: u8,
5741 };
5742
5743 pub const Pointer = struct {
5744 is_const: bool,
5745 is_volatile: bool,
5746 alignment: u32,
5747 child: type,
5748 };
5749
5750 pub const Array = struct {
5751 len: usize,
5752 child: type,
5753 };
5754
5755 pub const ContainerLayout = enum {
5756 Auto,
5757 Extern,
5758 Packed,
5759 };
5760
5761 pub const StructField = struct {
5762 name: []const u8,
5763 offset: ?usize,
5764 field_type: type,
5765 };
5766
5767 pub const Struct = struct {
5768 layout: ContainerLayout,
5769 fields: []StructField,
5770 defs: []Definition,
5771 };
5772
5773 pub const Nullable = struct {
5774 child: type,
5775 };
5776
5777 pub const ErrorUnion = struct {
5778 error_set: type,
5779 payload: type,
5780 };
5781
5782 pub const Error = struct {
5783 name: []const u8,
5784 value: usize,
5785 };
5786
5787 pub const ErrorSet = struct {
5788 errors: []Error,
5789 };
5790
5791 pub const EnumField = struct {
5792 name: []const u8,
5793 value: usize,
5794 };
5795
5796 pub const Enum = struct {
5797 layout: ContainerLayout,
5798 tag_type: type,
5799 fields: []EnumField,
5800 defs: []Definition,
5801 };
5802
5803 pub const UnionField = struct {
5804 name: []const u8,
5805 enum_field: ?EnumField,
5806 field_type: type,
5807 };
5808
5809 pub const Union = struct {
5810 layout: ContainerLayout,
5811 tag_type: type,
5812 fields: []UnionField,
5813 defs: []Definition,
5814 };
5815
5816 pub const CallingConvention = enum {
5817 Unspecified,
5818 C,
5819 Cold,
5820 Naked,
5821 Stdcall,
5822 Async,
5823 };
5824
5825 pub const FnArg = struct {
5826 is_generic: bool,
5827 is_noalias: bool,
5828 arg_type: type,
5829 };
5830
5831 pub const Fn = struct {
5832 calling_convention: CallingConvention,
5833 is_generic: bool,
5834 is_var_args: bool,
5835 return_type: type,
5836 async_allocator_type: type,
5837 args: []FnArg,
5838 };
5839
5840 pub const Promise = struct {
5841 child: type,
5842 };
5843
5844 pub const Definition = struct {
5845 name: []const u8,
5846 is_pub: bool,
5847 data: Data,
5848
5849 pub const Data = union(enum) {
5850 Type: type,
5851 Var: type,
5852 Fn: FnDef,
5853
5854 pub const FnDef = struct {
5855 fn_type: type,
5856 inline_type: Inline,
5857 calling_convention: CallingConvention,
5858 is_var_args: bool,
5859 is_extern: bool,
5860 is_export: bool,
5861 lib_name: ?[]const u8,
5862 return_type: type,
5863 arg_names: [][] const u8,
5864
5865 pub const Inline = enum {
5866 Auto,
5867 Always,
5868 Never,
5869 };
5870 };
5871 };
5872 };
5873};
5874
5875pub const FloatMode = enum {
5876 Optimized,
5877 Strict,
5878};
5879
5880pub const Endian = enum {
5881 Big,
5882 Little,
5883};
5884
5885pub const endian = Endian.Little;
5886pub const is_test = true;
5887pub const os = Os.linux;
5888pub const arch = Arch.x86_64;
5889pub const environ = Environ.gnu;
5890pub const object_format = ObjectFormat.elf;
5891pub const mode = Mode.Debug;
5892pub const link_libc = false;
5893pub const have_error_return_tracing = true;
5894pub const __zig_test_fn_slice = {}; // overwritten later
5895 {#code_end#}
5996 {#builtin#}
58965997 {#see_also|Build Mode#}
58975998 {#header_close#}
58985999 {#header_open|Root Source File#}
......@@ -6053,8 +6154,7 @@ pub fn build(b: *Builder) void {
60536154 b.default_step.dependOn(&exe.step);
60546155}
60556156 {#code_end#}
6056 {#header_close#}
6057 {#header_open|Terminal#}
6157 <p class="file">terminal</p>
60586158 <pre><code class="shell">$ zig build
60596159$ ./test
60606160all your base are belong to us</code></pre>
......@@ -6367,9 +6467,9 @@ AsmInputItem = "[" Symbol "]" String "(" Expression ")"
63676467
63686468AsmClobbers= ":" list(String, ",")
63696469
6370UnwrapExpression = BoolOrExpression (UnwrapNullable | UnwrapError) | BoolOrExpression
6470UnwrapExpression = BoolOrExpression (UnwrapOptional | UnwrapError) | BoolOrExpression
63716471
6372UnwrapNullable = "??" Expression
6472UnwrapOptional = "orelse" Expression
63736473
63746474UnwrapError = "catch" option("|" Symbol "|") Expression
63756475
......@@ -6443,12 +6543,10 @@ MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
64436543
64446544PrefixOpExpression = PrefixOp TypeExpr | SuffixOpExpression
64456545
6446SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | PtrDerefExpression)
6546SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ".*" | ".?")
64476547
64486548FieldAccessExpression = "." Symbol
64496549
6450PtrDerefExpression = ".*"
6451
64526550FnCallExpression = "(" list(Expression, ",") ")"
64536551
64546552ArrayAccessExpression = "[" Expression "]"
......@@ -6461,7 +6559,7 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",")
64616559
64626560StructLiteralField = "." Symbol "=" Expression
64636561
6464PrefixOp = "!" | "-" | "~" | (("*" | "[*]") option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
6562PrefixOp = "!" | "-" | "~" | (("*" | "[*]") option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "-%" | "try" | "await"
64656563
64666564PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType
64676565
......@@ -6554,8 +6652,8 @@ hljs.registerLanguage("zig", function(t) {
65546652 },
65556653 a = t.IR + "\\s*\\(",
65566654 c = {
6557 keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong",
6558 built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall",
6655 keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong resume cancel await async orelse",
6656 built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall",
65596657 literal: "true false null undefined"
65606658 },
65616659 n = [e, t.CLCM, t.CBCM, s, r];
example/cat/main.zig+1-1
......@@ -7,7 +7,7 @@ const allocator = std.debug.global_allocator;
77
88pub fn main() !void {
99 var args_it = os.args();
10 const exe = try unwrapArg(??args_it.next(allocator));
10 const exe = try unwrapArg(args_it.next(allocator).?);
1111 var catted_anything = false;
1212 var stdout_file = try io.getStdOut();
1313
src-self-hosted/arg.zig+5-5
......@@ -99,7 +99,7 @@ pub const Args = struct {
9999 error.ArgumentNotInAllowedSet => {
100100 std.debug.warn("argument '{}' is invalid for flag '{}'\n", args[i], arg);
101101 std.debug.warn("allowed options are ");
102 for (??flag.allowed_set) |possible| {
102 for (flag.allowed_set.?) |possible| {
103103 std.debug.warn("'{}' ", possible);
104104 }
105105 std.debug.warn("\n");
......@@ -276,14 +276,14 @@ test "parse arguments" {
276276 debug.assert(!args.present("help2"));
277277 debug.assert(!args.present("init"));
278278
279 debug.assert(mem.eql(u8, ??args.single("build-file"), "build.zig"));
280 debug.assert(mem.eql(u8, ??args.single("color"), "on"));
279 debug.assert(mem.eql(u8, args.single("build-file").?, "build.zig"));
280 debug.assert(mem.eql(u8, args.single("color").?, "on"));
281281
282 const objects = ??args.many("object");
282 const objects = args.many("object").?;
283283 debug.assert(mem.eql(u8, objects[0], "obj1"));
284284 debug.assert(mem.eql(u8, objects[1], "obj2"));
285285
286 debug.assert(mem.eql(u8, ??args.single("library"), "lib2"));
286 debug.assert(mem.eql(u8, args.single("library").?, "lib2"));
287287
288288 const pos = args.positionals.toSliceConst();
289289 debug.assert(mem.eql(u8, pos[0], "build"));
src-self-hosted/introspect.zig+1-1
......@@ -27,7 +27,7 @@ pub fn findZigLibDir(allocator: *mem.Allocator) ![]u8 {
2727
2828 var cur_path: []const u8 = self_exe_path;
2929 while (true) {
30 const test_dir = os.path.dirname(cur_path);
30 const test_dir = os.path.dirname(cur_path) orelse ".";
3131
3232 if (mem.eql(u8, test_dir, cur_path)) {
3333 break;
src-self-hosted/llvm.zig+1-1
......@@ -8,6 +8,6 @@ pub const ContextRef = removeNullability(c.LLVMContextRef);
88pub const BuilderRef = removeNullability(c.LLVMBuilderRef);
99
1010fn removeNullability(comptime T: type) type {
11 comptime assert(@typeId(T) == builtin.TypeId.Nullable);
11 comptime assert(@typeId(T) == builtin.TypeId.Optional);
1212 return T.Child;
1313}
src-self-hosted/main.zig+13-13
......@@ -212,7 +212,7 @@ fn cmdBuild(allocator: *Allocator, args: []const []const u8) !void {
212212 const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig");
213213 defer allocator.free(build_runner_path);
214214
215 const build_file = flags.single("build-file") ?? "build.zig";
215 const build_file = flags.single("build-file") orelse "build.zig";
216216 const build_file_abs = try os.path.resolve(allocator, ".", build_file);
217217 defer allocator.free(build_file_abs);
218218
......@@ -249,7 +249,7 @@ fn cmdBuild(allocator: *Allocator, args: []const []const u8) !void {
249249 defer build_args.deinit();
250250
251251 const build_file_basename = os.path.basename(build_file_abs);
252 const build_file_dirname = os.path.dirname(build_file_abs);
252 const build_file_dirname = os.path.dirname(build_file_abs) orelse ".";
253253
254254 var full_cache_dir: []u8 = undefined;
255255 if (flags.single("cache-dir")) |cache_dir| {
......@@ -490,7 +490,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
490490 try stderr.print("encountered --pkg-end with no matching --pkg-begin\n");
491491 os.exit(1);
492492 }
493 cur_pkg = ??cur_pkg.parent;
493 cur_pkg = cur_pkg.parent.?;
494494 }
495495 }
496496
......@@ -514,28 +514,28 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
514514 },
515515 }
516516
517 const basename = os.path.basename(??in_file);
517 const basename = os.path.basename(in_file.?);
518518 var it = mem.split(basename, ".");
519 const root_name = it.next() ?? {
519 const root_name = it.next() orelse {
520520 try stderr.write("file name cannot be empty\n");
521521 os.exit(1);
522522 };
523523
524524 const asm_a = flags.many("assembly");
525525 const obj_a = flags.many("object");
526 if (in_file == null and (obj_a == null or (??obj_a).len == 0) and (asm_a == null or (??asm_a).len == 0)) {
526 if (in_file == null and (obj_a == null or obj_a.?.len == 0) and (asm_a == null or asm_a.?.len == 0)) {
527527 try stderr.write("Expected source file argument or at least one --object or --assembly argument\n");
528528 os.exit(1);
529529 }
530530
531 if (out_type == Module.Kind.Obj and (obj_a != null and (??obj_a).len != 0)) {
531 if (out_type == Module.Kind.Obj and (obj_a != null and obj_a.?.len != 0)) {
532532 try stderr.write("When building an object file, --object arguments are invalid\n");
533533 os.exit(1);
534534 }
535535
536536 const zig_root_source_file = in_file;
537537
538 const full_cache_dir = os.path.resolve(allocator, ".", flags.single("cache-dir") ?? "zig-cache"[0..]) catch {
538 const full_cache_dir = os.path.resolve(allocator, ".", flags.single("cache-dir") orelse "zig-cache"[0..]) catch {
539539 os.exit(1);
540540 };
541541 defer allocator.free(full_cache_dir);
......@@ -555,9 +555,9 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
555555 );
556556 defer module.destroy();
557557
558 module.version_major = try std.fmt.parseUnsigned(u32, flags.single("ver-major") ?? "0", 10);
559 module.version_minor = try std.fmt.parseUnsigned(u32, flags.single("ver-minor") ?? "0", 10);
560 module.version_patch = try std.fmt.parseUnsigned(u32, flags.single("ver-patch") ?? "0", 10);
558 module.version_major = try std.fmt.parseUnsigned(u32, flags.single("ver-major") orelse "0", 10);
559 module.version_minor = try std.fmt.parseUnsigned(u32, flags.single("ver-minor") orelse "0", 10);
560 module.version_patch = try std.fmt.parseUnsigned(u32, flags.single("ver-patch") orelse "0", 10);
561561
562562 module.is_test = false;
563563
......@@ -652,7 +652,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
652652 }
653653
654654 try module.build();
655 try module.link(flags.single("out-file") ?? null);
655 try module.link(flags.single("out-file") orelse null);
656656
657657 if (flags.present("print-timing-info")) {
658658 // codegen_print_timing_info(g, stderr);
......@@ -734,7 +734,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
734734 defer file.close();
735735
736736 const source_code = io.readFileAlloc(allocator, file_path) catch |err| {
737 try stderr.print("unable to open '{}': {}", file_path, err);
737 try stderr.print("unable to open '{}': {}\n", file_path, err);
738738 fmt_errors = true;
739739 continue;
740740 };
src-self-hosted/module.zig+4-4
......@@ -130,13 +130,13 @@ pub const Module = struct {
130130 var name_buffer = try Buffer.init(allocator, name);
131131 errdefer name_buffer.deinit();
132132
133 const context = c.LLVMContextCreate() ?? return error.OutOfMemory;
133 const context = c.LLVMContextCreate() orelse return error.OutOfMemory;
134134 errdefer c.LLVMContextDispose(context);
135135
136 const module = c.LLVMModuleCreateWithNameInContext(name_buffer.ptr(), context) ?? return error.OutOfMemory;
136 const module = c.LLVMModuleCreateWithNameInContext(name_buffer.ptr(), context) orelse return error.OutOfMemory;
137137 errdefer c.LLVMDisposeModule(module);
138138
139 const builder = c.LLVMCreateBuilderInContext(context) ?? return error.OutOfMemory;
139 const builder = c.LLVMCreateBuilderInContext(context) orelse return error.OutOfMemory;
140140 errdefer c.LLVMDisposeBuilder(builder);
141141
142142 const module_ptr = try allocator.create(Module);
......@@ -223,7 +223,7 @@ pub const Module = struct {
223223 c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr);
224224 }
225225
226 const root_src_path = self.root_src_path ?? @panic("TODO handle null root src path");
226 const root_src_path = self.root_src_path orelse @panic("TODO handle null root src path");
227227 const root_src_real_path = os.path.real(self.allocator, root_src_path) catch |err| {
228228 try printError("unable to get real path '{}': {}", root_src_path, err);
229229 return err;
src/all_types.hpp+39-33
......@@ -144,6 +144,9 @@ enum ConstPtrSpecial {
144144 // understand the value of pointee at compile time. However, we will still
145145 // emit a binary with a compile time known address.
146146 // In this case index is the numeric address value.
147 // We also use this for null pointer. We need the data layout for ConstCastOnly == true
148 // types to be the same, so all optionals of pointer types use x_ptr
149 // instead of x_optional
147150 ConstPtrSpecialHardCodedAddr,
148151 // This means that the pointer represents memory of assigning to _.
149152 // That is, storing discards the data, and loading is invalid.
......@@ -219,10 +222,10 @@ enum RuntimeHintErrorUnion {
219222 RuntimeHintErrorUnionNonError,
220223};
221224
222enum RuntimeHintMaybe {
223 RuntimeHintMaybeUnknown,
224 RuntimeHintMaybeNull, // TODO is this value even possible? if this is the case it might mean the const value is compile time known.
225 RuntimeHintMaybeNonNull,
225enum RuntimeHintOptional {
226 RuntimeHintOptionalUnknown,
227 RuntimeHintOptionalNull, // TODO is this value even possible? if this is the case it might mean the const value is compile time known.
228 RuntimeHintOptionalNonNull,
226229};
227230
228231enum RuntimeHintPtr {
......@@ -251,7 +254,7 @@ struct ConstExprValue {
251254 bool x_bool;
252255 ConstBoundFnValue x_bound_fn;
253256 TypeTableEntry *x_type;
254 ConstExprValue *x_maybe;
257 ConstExprValue *x_optional;
255258 ConstErrValue x_err_union;
256259 ErrorTableEntry *x_err_set;
257260 BigInt x_enum_tag;
......@@ -265,7 +268,7 @@ struct ConstExprValue {
265268
266269 // populated if special == ConstValSpecialRuntime
267270 RuntimeHintErrorUnion rh_error_union;
268 RuntimeHintMaybe rh_maybe;
271 RuntimeHintOptional rh_maybe;
269272 RuntimeHintPtr rh_ptr;
270273 } data;
271274};
......@@ -384,6 +387,7 @@ enum NodeType {
384387 NodeTypeSliceExpr,
385388 NodeTypeFieldAccessExpr,
386389 NodeTypePtrDeref,
390 NodeTypeUnwrapOptional,
387391 NodeTypeUse,
388392 NodeTypeBoolLiteral,
389393 NodeTypeNullLiteral,
......@@ -553,7 +557,7 @@ enum BinOpType {
553557 BinOpTypeMultWrap,
554558 BinOpTypeDiv,
555559 BinOpTypeMod,
556 BinOpTypeUnwrapMaybe,
560 BinOpTypeUnwrapOptional,
557561 BinOpTypeArrayCat,
558562 BinOpTypeArrayMult,
559563 BinOpTypeErrorUnion,
......@@ -572,6 +576,10 @@ struct AstNodeCatchExpr {
572576 AstNode *op2;
573577};
574578
579struct AstNodeUnwrapOptional {
580 AstNode *expr;
581};
582
575583enum CastOp {
576584 CastOpNoCast, // signifies the function call expression is not a cast
577585 CastOpNoop, // fn call expr is a cast, but does nothing
......@@ -583,6 +591,7 @@ enum CastOp {
583591 CastOpNumLitToConcrete,
584592 CastOpErrSet,
585593 CastOpBitCast,
594 CastOpPtrOfArrayToSlice,
586595};
587596
588597struct AstNodeFnCallExpr {
......@@ -619,8 +628,7 @@ enum PrefixOp {
619628 PrefixOpBinNot,
620629 PrefixOpNegation,
621630 PrefixOpNegationWrap,
622 PrefixOpMaybe,
623 PrefixOpUnwrapMaybe,
631 PrefixOpOptional,
624632 PrefixOpAddrOf,
625633};
626634
......@@ -905,6 +913,7 @@ struct AstNode {
905913 AstNodeTestDecl test_decl;
906914 AstNodeBinOpExpr bin_op_expr;
907915 AstNodeCatchExpr unwrap_err_expr;
916 AstNodeUnwrapOptional unwrap_optional;
908917 AstNodePrefixOpExpr prefix_op_expr;
909918 AstNodePointerType pointer_type;
910919 AstNodeFnCallExpr fn_call_expr;
......@@ -1037,6 +1046,10 @@ struct TypeTableEntryStruct {
10371046 // whether we've finished resolving it
10381047 bool complete;
10391048
1049 // whether any of the fields require comptime
1050 // the value is not valid until zero_bits_known == true
1051 bool requires_comptime;
1052
10401053 bool zero_bits_loop_flag;
10411054 bool zero_bits_known;
10421055 uint32_t abi_alignment; // also figured out with zero_bits pass
......@@ -1044,7 +1057,7 @@ struct TypeTableEntryStruct {
10441057 HashMap<Buf *, TypeStructField *, buf_hash, buf_eql_buf> fields_by_name;
10451058};
10461059
1047struct TypeTableEntryMaybe {
1060struct TypeTableEntryOptional {
10481061 TypeTableEntry *child_type;
10491062};
10501063
......@@ -1078,8 +1091,7 @@ struct TypeTableEntryEnum {
10781091 bool zero_bits_loop_flag;
10791092 bool zero_bits_known;
10801093
1081 bool generate_name_table;
1082 LLVMValueRef name_table;
1094 LLVMValueRef name_function;
10831095
10841096 HashMap<Buf *, TypeEnumField *, buf_hash, buf_eql_buf> fields_by_name;
10851097};
......@@ -1105,6 +1117,10 @@ struct TypeTableEntryUnion {
11051117 // whether we've finished resolving it
11061118 bool complete;
11071119
1120 // whether any of the fields require comptime
1121 // the value is not valid until zero_bits_known == true
1122 bool requires_comptime;
1123
11081124 bool zero_bits_loop_flag;
11091125 bool zero_bits_known;
11101126 uint32_t abi_alignment; // also figured out with zero_bits pass
......@@ -1163,7 +1179,7 @@ enum TypeTableEntryId {
11631179 TypeTableEntryIdComptimeInt,
11641180 TypeTableEntryIdUndefined,
11651181 TypeTableEntryIdNull,
1166 TypeTableEntryIdMaybe,
1182 TypeTableEntryIdOptional,
11671183 TypeTableEntryIdErrorUnion,
11681184 TypeTableEntryIdErrorSet,
11691185 TypeTableEntryIdEnum,
......@@ -1194,7 +1210,7 @@ struct TypeTableEntry {
11941210 TypeTableEntryFloat floating;
11951211 TypeTableEntryArray array;
11961212 TypeTableEntryStruct structure;
1197 TypeTableEntryMaybe maybe;
1213 TypeTableEntryOptional maybe;
11981214 TypeTableEntryErrorUnion error_union;
11991215 TypeTableEntryErrorSet error_set;
12001216 TypeTableEntryEnum enumeration;
......@@ -1346,7 +1362,6 @@ enum BuiltinFnId {
13461362 BuiltinFnIdSetRuntimeSafety,
13471363 BuiltinFnIdSetFloatMode,
13481364 BuiltinFnIdTypeName,
1349 BuiltinFnIdCanImplicitCast,
13501365 BuiltinFnIdPanic,
13511366 BuiltinFnIdPtrCast,
13521367 BuiltinFnIdBitCast,
......@@ -1391,10 +1406,11 @@ enum PanicMsgId {
13911406 PanicMsgIdRemainderDivisionByZero,
13921407 PanicMsgIdExactDivisionRemainder,
13931408 PanicMsgIdSliceWidenRemainder,
1394 PanicMsgIdUnwrapMaybeFail,
1409 PanicMsgIdUnwrapOptionalFail,
13951410 PanicMsgIdInvalidErrorCode,
13961411 PanicMsgIdIncorrectAlignment,
13971412 PanicMsgIdBadUnionField,
1413 PanicMsgIdBadEnumValue,
13981414
13991415 PanicMsgIdCount,
14001416};
......@@ -1712,8 +1728,6 @@ struct CodeGen {
17121728 ZigList<Buf *> link_objects;
17131729 ZigList<Buf *> assembly_files;
17141730
1715 ZigList<TypeTableEntry *> name_table_enums;
1716
17171731 Buf *test_filter;
17181732 Buf *test_name_prefix;
17191733
......@@ -2003,8 +2017,8 @@ enum IrInstructionId {
20032017 IrInstructionIdAsm,
20042018 IrInstructionIdSizeOf,
20052019 IrInstructionIdTestNonNull,
2006 IrInstructionIdUnwrapMaybe,
2007 IrInstructionIdMaybeWrap,
2020 IrInstructionIdUnwrapOptional,
2021 IrInstructionIdOptionalWrap,
20082022 IrInstructionIdUnionTag,
20092023 IrInstructionIdClz,
20102024 IrInstructionIdCtz,
......@@ -2055,7 +2069,6 @@ enum IrInstructionId {
20552069 IrInstructionIdCheckSwitchProngs,
20562070 IrInstructionIdCheckStatementIsVoid,
20572071 IrInstructionIdTypeName,
2058 IrInstructionIdCanImplicitCast,
20592072 IrInstructionIdDeclRef,
20602073 IrInstructionIdPanic,
20612074 IrInstructionIdTagName,
......@@ -2172,7 +2185,7 @@ enum IrUnOp {
21722185 IrUnOpNegation,
21732186 IrUnOpNegationWrap,
21742187 IrUnOpDereference,
2175 IrUnOpMaybe,
2188 IrUnOpOptional,
21762189};
21772190
21782191struct IrInstructionUnOp {
......@@ -2475,7 +2488,7 @@ struct IrInstructionTestNonNull {
24752488 IrInstruction *value;
24762489};
24772490
2478struct IrInstructionUnwrapMaybe {
2491struct IrInstructionUnwrapOptional {
24792492 IrInstruction base;
24802493
24812494 IrInstruction *value;
......@@ -2733,7 +2746,7 @@ struct IrInstructionUnwrapErrPayload {
27332746 bool safety_check_on;
27342747};
27352748
2736struct IrInstructionMaybeWrap {
2749struct IrInstructionOptionalWrap {
27372750 IrInstruction base;
27382751
27392752 IrInstruction *value;
......@@ -2848,13 +2861,6 @@ struct IrInstructionTypeName {
28482861 IrInstruction *type_value;
28492862};
28502863
2851struct IrInstructionCanImplicitCast {
2852 IrInstruction base;
2853
2854 IrInstruction *type_value;
2855 IrInstruction *target_value;
2856};
2857
28582864struct IrInstructionDeclRef {
28592865 IrInstruction base;
28602866
......@@ -2949,10 +2955,10 @@ struct IrInstructionExport {
29492955struct IrInstructionErrorReturnTrace {
29502956 IrInstruction base;
29512957
2952 enum Nullable {
2958 enum Optional {
29532959 Null,
29542960 NonNull,
2955 } nullable;
2961 } optional;
29562962};
29572963
29582964struct IrInstructionErrorUnion {
src/analyze.cpp+215-161
......@@ -236,7 +236,7 @@ bool type_is_complete(TypeTableEntry *type_entry) {
236236 case TypeTableEntryIdComptimeInt:
237237 case TypeTableEntryIdUndefined:
238238 case TypeTableEntryIdNull:
239 case TypeTableEntryIdMaybe:
239 case TypeTableEntryIdOptional:
240240 case TypeTableEntryIdErrorUnion:
241241 case TypeTableEntryIdErrorSet:
242242 case TypeTableEntryIdFn:
......@@ -272,7 +272,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) {
272272 case TypeTableEntryIdComptimeInt:
273273 case TypeTableEntryIdUndefined:
274274 case TypeTableEntryIdNull:
275 case TypeTableEntryIdMaybe:
275 case TypeTableEntryIdOptional:
276276 case TypeTableEntryIdErrorUnion:
277277 case TypeTableEntryIdErrorSet:
278278 case TypeTableEntryIdFn:
......@@ -384,6 +384,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
384384 bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count)
385385{
386386 assert(!type_is_invalid(child_type));
387 assert(ptr_len == PtrLenSingle || child_type->id != TypeTableEntryIdOpaque);
387388
388389 TypeId type_id = {};
389390 TypeTableEntry **parent_pointer = nullptr;
......@@ -519,9 +520,8 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
519520 } else {
520521 ensure_complete_type(g, child_type);
521522
522 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMaybe);
523 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdOptional);
523524 assert(child_type->type_ref || child_type->zero_bits);
524 assert(child_type->di_type);
525525 entry->is_copyable = type_is_copyable(g, child_type);
526526
527527 buf_resize(&entry->name, 0);
......@@ -531,12 +531,14 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
531531 entry->type_ref = LLVMInt1Type();
532532 entry->di_type = g->builtin_types.entry_bool->di_type;
533533 } else if (type_is_codegen_pointer(child_type)) {
534 assert(child_type->di_type);
534535 // this is an optimization but also is necessary for calling C
535536 // functions where all pointers are maybe pointers
536537 // function types are technically pointers
537538 entry->type_ref = child_type->type_ref;
538539 entry->di_type = child_type->di_type;
539540 } else {
541 assert(child_type->di_type);
540542 // create a struct with a boolean whether this is the null value
541543 LLVMTypeRef elem_types[] = {
542544 child_type->type_ref,
......@@ -1360,7 +1362,7 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
13601362 return type_entry->data.structure.layout == ContainerLayoutPacked;
13611363 case TypeTableEntryIdUnion:
13621364 return type_entry->data.unionation.layout == ContainerLayoutPacked;
1363 case TypeTableEntryIdMaybe:
1365 case TypeTableEntryIdOptional:
13641366 {
13651367 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
13661368 return type_is_codegen_pointer(child_type);
......@@ -1414,7 +1416,7 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
14141416 return type_allowed_in_extern(g, type_entry->data.pointer.child_type);
14151417 case TypeTableEntryIdStruct:
14161418 return type_entry->data.structure.layout == ContainerLayoutExtern || type_entry->data.structure.layout == ContainerLayoutPacked;
1417 case TypeTableEntryIdMaybe:
1419 case TypeTableEntryIdOptional:
14181420 {
14191421 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
14201422 return child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn;
......@@ -1537,7 +1539,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
15371539 case TypeTableEntryIdPointer:
15381540 case TypeTableEntryIdArray:
15391541 case TypeTableEntryIdStruct:
1540 case TypeTableEntryIdMaybe:
1542 case TypeTableEntryIdOptional:
15411543 case TypeTableEntryIdErrorUnion:
15421544 case TypeTableEntryIdErrorSet:
15431545 case TypeTableEntryIdEnum:
......@@ -1631,7 +1633,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
16311633 case TypeTableEntryIdPointer:
16321634 case TypeTableEntryIdArray:
16331635 case TypeTableEntryIdStruct:
1634 case TypeTableEntryIdMaybe:
1636 case TypeTableEntryIdOptional:
16351637 case TypeTableEntryIdErrorUnion:
16361638 case TypeTableEntryIdErrorSet:
16371639 case TypeTableEntryIdEnum:
......@@ -2532,6 +2534,10 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
25322534 continue;
25332535 }
25342536
2537 if (type_requires_comptime(field_type)) {
2538 struct_type->data.structure.requires_comptime = true;
2539 }
2540
25352541 if (!type_has_bits(field_type))
25362542 continue;
25372543
......@@ -2723,6 +2729,11 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
27232729 }
27242730 union_field->type_entry = field_type;
27252731
2732 if (type_requires_comptime(field_type)) {
2733 union_type->data.unionation.requires_comptime = true;
2734 }
2735
2736
27262737 if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
27272738 ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
27282739 buf_sprintf("non-enum union field assignment"));
......@@ -2975,8 +2986,8 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {
29752986 return wrong_panic_prototype(g, proto_node, fn_type);
29762987 }
29772988
2978 TypeTableEntry *nullable_ptr_to_stack_trace_type = get_maybe_type(g, get_ptr_to_stack_trace_type(g));
2979 if (fn_type_id->param_info[1].type != nullable_ptr_to_stack_trace_type) {
2989 TypeTableEntry *optional_ptr_to_stack_trace_type = get_maybe_type(g, get_ptr_to_stack_trace_type(g));
2990 if (fn_type_id->param_info[1].type != optional_ptr_to_stack_trace_type) {
29802991 return wrong_panic_prototype(g, proto_node, fn_type);
29812992 }
29822993
......@@ -3298,6 +3309,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
32983309 case NodeTypeAsmExpr:
32993310 case NodeTypeFieldAccessExpr:
33003311 case NodeTypePtrDeref:
3312 case NodeTypeUnwrapOptional:
33013313 case NodeTypeStructField:
33023314 case NodeTypeContainerInitExpr:
33033315 case NodeTypeStructValueField:
......@@ -3358,7 +3370,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
33583370 case TypeTableEntryIdPointer:
33593371 case TypeTableEntryIdArray:
33603372 case TypeTableEntryIdStruct:
3361 case TypeTableEntryIdMaybe:
3373 case TypeTableEntryIdOptional:
33623374 case TypeTableEntryIdErrorUnion:
33633375 case TypeTableEntryIdErrorSet:
33643376 case TypeTableEntryIdEnum:
......@@ -3736,7 +3748,7 @@ static bool is_container(TypeTableEntry *type_entry) {
37363748 case TypeTableEntryIdComptimeInt:
37373749 case TypeTableEntryIdUndefined:
37383750 case TypeTableEntryIdNull:
3739 case TypeTableEntryIdMaybe:
3751 case TypeTableEntryIdOptional:
37403752 case TypeTableEntryIdErrorUnion:
37413753 case TypeTableEntryIdErrorSet:
37423754 case TypeTableEntryIdFn:
......@@ -3751,14 +3763,24 @@ static bool is_container(TypeTableEntry *type_entry) {
37513763 zig_unreachable();
37523764}
37533765
3766bool is_ref(TypeTableEntry *type_entry) {
3767 return type_entry->id == TypeTableEntryIdPointer && type_entry->data.pointer.ptr_len == PtrLenSingle;
3768}
3769
3770bool is_array_ref(TypeTableEntry *type_entry) {
3771 TypeTableEntry *array = is_ref(type_entry) ?
3772 type_entry->data.pointer.child_type : type_entry;
3773 return array->id == TypeTableEntryIdArray;
3774}
3775
37543776bool is_container_ref(TypeTableEntry *type_entry) {
3755 return (type_entry->id == TypeTableEntryIdPointer) ?
3777 return is_ref(type_entry) ?
37563778 is_container(type_entry->data.pointer.child_type) : is_container(type_entry);
37573779}
37583780
37593781TypeTableEntry *container_ref_type(TypeTableEntry *type_entry) {
37603782 assert(is_container_ref(type_entry));
3761 return (type_entry->id == TypeTableEntryIdPointer) ?
3783 return is_ref(type_entry) ?
37623784 type_entry->data.pointer.child_type : type_entry;
37633785}
37643786
......@@ -3785,7 +3807,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
37853807 case TypeTableEntryIdComptimeInt:
37863808 case TypeTableEntryIdUndefined:
37873809 case TypeTableEntryIdNull:
3788 case TypeTableEntryIdMaybe:
3810 case TypeTableEntryIdOptional:
37893811 case TypeTableEntryIdErrorUnion:
37903812 case TypeTableEntryIdErrorSet:
37913813 case TypeTableEntryIdFn:
......@@ -3804,7 +3826,7 @@ TypeTableEntry *get_codegen_ptr_type(TypeTableEntry *type) {
38043826 if (type->id == TypeTableEntryIdPointer) return type;
38053827 if (type->id == TypeTableEntryIdFn) return type;
38063828 if (type->id == TypeTableEntryIdPromise) return type;
3807 if (type->id == TypeTableEntryIdMaybe) {
3829 if (type->id == TypeTableEntryIdOptional) {
38083830 if (type->data.maybe.child_type->id == TypeTableEntryIdPointer) return type->data.maybe.child_type;
38093831 if (type->data.maybe.child_type->id == TypeTableEntryIdFn) return type->data.maybe.child_type;
38103832 if (type->data.maybe.child_type->id == TypeTableEntryIdPromise) return type->data.maybe.child_type;
......@@ -4311,7 +4333,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
43114333 return type_has_bits(type_entry);
43124334 case TypeTableEntryIdErrorUnion:
43134335 return type_has_bits(type_entry->data.error_union.payload_type);
4314 case TypeTableEntryIdMaybe:
4336 case TypeTableEntryIdOptional:
43154337 return type_has_bits(type_entry->data.maybe.child_type) &&
43164338 !type_is_codegen_pointer(type_entry->data.maybe.child_type);
43174339 case TypeTableEntryIdUnion:
......@@ -4558,6 +4580,52 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
45584580 return true;
45594581}
45604582
4583static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
4584 uint32_t hash_val = 0;
4585 switch (const_val->data.x_ptr.mut) {
4586 case ConstPtrMutRuntimeVar:
4587 hash_val += (uint32_t)3500721036;
4588 break;
4589 case ConstPtrMutComptimeConst:
4590 hash_val += (uint32_t)4214318515;
4591 break;
4592 case ConstPtrMutComptimeVar:
4593 hash_val += (uint32_t)1103195694;
4594 break;
4595 }
4596 switch (const_val->data.x_ptr.special) {
4597 case ConstPtrSpecialInvalid:
4598 zig_unreachable();
4599 case ConstPtrSpecialRef:
4600 hash_val += (uint32_t)2478261866;
4601 hash_val += hash_ptr(const_val->data.x_ptr.data.ref.pointee);
4602 return hash_val;
4603 case ConstPtrSpecialBaseArray:
4604 hash_val += (uint32_t)1764906839;
4605 hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val);
4606 hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index);
4607 hash_val += const_val->data.x_ptr.data.base_array.is_cstr ? 1297263887 : 200363492;
4608 return hash_val;
4609 case ConstPtrSpecialBaseStruct:
4610 hash_val += (uint32_t)3518317043;
4611 hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val);
4612 hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index);
4613 return hash_val;
4614 case ConstPtrSpecialHardCodedAddr:
4615 hash_val += (uint32_t)4048518294;
4616 hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr);
4617 return hash_val;
4618 case ConstPtrSpecialDiscard:
4619 hash_val += 2010123162;
4620 return hash_val;
4621 case ConstPtrSpecialFunction:
4622 hash_val += (uint32_t)2590901619;
4623 hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
4624 return hash_val;
4625 }
4626 zig_unreachable();
4627}
4628
45614629static uint32_t hash_const_val(ConstExprValue *const_val) {
45624630 assert(const_val->special == ConstValSpecialStatic);
45634631 switch (const_val->type->id) {
......@@ -4626,51 +4694,7 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
46264694 assert(const_val->data.x_ptr.special == ConstPtrSpecialFunction);
46274695 return 3677364617 ^ hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
46284696 case TypeTableEntryIdPointer:
4629 {
4630 uint32_t hash_val = 0;
4631 switch (const_val->data.x_ptr.mut) {
4632 case ConstPtrMutRuntimeVar:
4633 hash_val += (uint32_t)3500721036;
4634 break;
4635 case ConstPtrMutComptimeConst:
4636 hash_val += (uint32_t)4214318515;
4637 break;
4638 case ConstPtrMutComptimeVar:
4639 hash_val += (uint32_t)1103195694;
4640 break;
4641 }
4642 switch (const_val->data.x_ptr.special) {
4643 case ConstPtrSpecialInvalid:
4644 zig_unreachable();
4645 case ConstPtrSpecialRef:
4646 hash_val += (uint32_t)2478261866;
4647 hash_val += hash_ptr(const_val->data.x_ptr.data.ref.pointee);
4648 return hash_val;
4649 case ConstPtrSpecialBaseArray:
4650 hash_val += (uint32_t)1764906839;
4651 hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val);
4652 hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index);
4653 hash_val += const_val->data.x_ptr.data.base_array.is_cstr ? 1297263887 : 200363492;
4654 return hash_val;
4655 case ConstPtrSpecialBaseStruct:
4656 hash_val += (uint32_t)3518317043;
4657 hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val);
4658 hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index);
4659 return hash_val;
4660 case ConstPtrSpecialHardCodedAddr:
4661 hash_val += (uint32_t)4048518294;
4662 hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr);
4663 return hash_val;
4664 case ConstPtrSpecialDiscard:
4665 hash_val += 2010123162;
4666 return hash_val;
4667 case ConstPtrSpecialFunction:
4668 hash_val += (uint32_t)2590901619;
4669 hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
4670 return hash_val;
4671 }
4672 zig_unreachable();
4673 }
4697 return hash_const_val_ptr(const_val);
46744698 case TypeTableEntryIdPromise:
46754699 // TODO better hashing algorithm
46764700 return 223048345;
......@@ -4687,11 +4711,15 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
46874711 case TypeTableEntryIdUnion:
46884712 // TODO better hashing algorithm
46894713 return 2709806591;
4690 case TypeTableEntryIdMaybe:
4691 if (const_val->data.x_maybe) {
4692 return hash_const_val(const_val->data.x_maybe) * 1992916303;
4714 case TypeTableEntryIdOptional:
4715 if (get_codegen_ptr_type(const_val->type) != nullptr) {
4716 return hash_const_val(const_val) * 1992916303;
46934717 } else {
4694 return 4016830364;
4718 if (const_val->data.x_optional) {
4719 return hash_const_val(const_val->data.x_optional) * 1992916303;
4720 } else {
4721 return 4016830364;
4722 }
46954723 }
46964724 case TypeTableEntryIdErrorUnion:
46974725 // TODO better hashing algorithm
......@@ -4791,10 +4819,12 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
47914819 }
47924820 return false;
47934821
4794 case TypeTableEntryIdMaybe:
4795 if (value->data.x_maybe == nullptr)
4822 case TypeTableEntryIdOptional:
4823 if (get_codegen_ptr_type(value->type) != nullptr)
4824 return value->data.x_ptr.mut == ConstPtrMutComptimeVar;
4825 if (value->data.x_optional == nullptr)
47964826 return false;
4797 return can_mutate_comptime_var_state(value->data.x_maybe);
4827 return can_mutate_comptime_var_state(value->data.x_optional);
47984828
47994829 case TypeTableEntryIdErrorUnion:
48004830 if (value->data.x_err_union.err != nullptr)
......@@ -4841,7 +4871,7 @@ static bool return_type_is_cacheable(TypeTableEntry *return_type) {
48414871 case TypeTableEntryIdUnion:
48424872 return false;
48434873
4844 case TypeTableEntryIdMaybe:
4874 case TypeTableEntryIdOptional:
48454875 return return_type_is_cacheable(return_type->data.maybe.child_type);
48464876
48474877 case TypeTableEntryIdErrorUnion:
......@@ -4943,17 +4973,29 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
49434973 case TypeTableEntryIdArgTuple:
49444974 return true;
49454975 case TypeTableEntryIdArray:
4976 return type_requires_comptime(type_entry->data.array.child_type);
49464977 case TypeTableEntryIdStruct:
4978 assert(type_has_zero_bits_known(type_entry));
4979 return type_entry->data.structure.requires_comptime;
49474980 case TypeTableEntryIdUnion:
4948 case TypeTableEntryIdMaybe:
4981 assert(type_has_zero_bits_known(type_entry));
4982 return type_entry->data.unionation.requires_comptime;
4983 case TypeTableEntryIdOptional:
4984 return type_requires_comptime(type_entry->data.maybe.child_type);
49494985 case TypeTableEntryIdErrorUnion:
4986 return type_requires_comptime(type_entry->data.error_union.payload_type);
4987 case TypeTableEntryIdPointer:
4988 if (type_entry->data.pointer.child_type->id == TypeTableEntryIdOpaque) {
4989 return false;
4990 } else {
4991 return type_requires_comptime(type_entry->data.pointer.child_type);
4992 }
49504993 case TypeTableEntryIdEnum:
49514994 case TypeTableEntryIdErrorSet:
49524995 case TypeTableEntryIdFn:
49534996 case TypeTableEntryIdBool:
49544997 case TypeTableEntryIdInt:
49554998 case TypeTableEntryIdFloat:
4956 case TypeTableEntryIdPointer:
49574999 case TypeTableEntryIdVoid:
49585000 case TypeTableEntryIdUnreachable:
49595001 case TypeTableEntryIdPromise:
......@@ -5308,6 +5350,52 @@ bool ir_get_var_is_comptime(VariableTableEntry *var) {
53085350 return var->is_comptime->value.data.x_bool;
53095351}
53105352
5353bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) {
5354 if (a->data.x_ptr.special != b->data.x_ptr.special)
5355 return false;
5356 if (a->data.x_ptr.mut != b->data.x_ptr.mut)
5357 return false;
5358 switch (a->data.x_ptr.special) {
5359 case ConstPtrSpecialInvalid:
5360 zig_unreachable();
5361 case ConstPtrSpecialRef:
5362 if (a->data.x_ptr.data.ref.pointee != b->data.x_ptr.data.ref.pointee)
5363 return false;
5364 return true;
5365 case ConstPtrSpecialBaseArray:
5366 if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val &&
5367 a->data.x_ptr.data.base_array.array_val->global_refs !=
5368 b->data.x_ptr.data.base_array.array_val->global_refs)
5369 {
5370 return false;
5371 }
5372 if (a->data.x_ptr.data.base_array.elem_index != b->data.x_ptr.data.base_array.elem_index)
5373 return false;
5374 if (a->data.x_ptr.data.base_array.is_cstr != b->data.x_ptr.data.base_array.is_cstr)
5375 return false;
5376 return true;
5377 case ConstPtrSpecialBaseStruct:
5378 if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val &&
5379 a->data.x_ptr.data.base_struct.struct_val->global_refs !=
5380 b->data.x_ptr.data.base_struct.struct_val->global_refs)
5381 {
5382 return false;
5383 }
5384 if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index)
5385 return false;
5386 return true;
5387 case ConstPtrSpecialHardCodedAddr:
5388 if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr)
5389 return false;
5390 return true;
5391 case ConstPtrSpecialDiscard:
5392 return true;
5393 case ConstPtrSpecialFunction:
5394 return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry;
5395 }
5396 zig_unreachable();
5397}
5398
53115399bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
53125400 assert(a->type->id == b->type->id);
53135401 assert(a->special == ConstValSpecialStatic);
......@@ -5359,49 +5447,7 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
53595447 return bigint_cmp(&a->data.x_bigint, &b->data.x_bigint) == CmpEQ;
53605448 case TypeTableEntryIdPointer:
53615449 case TypeTableEntryIdFn:
5362 if (a->data.x_ptr.special != b->data.x_ptr.special)
5363 return false;
5364 if (a->data.x_ptr.mut != b->data.x_ptr.mut)
5365 return false;
5366 switch (a->data.x_ptr.special) {
5367 case ConstPtrSpecialInvalid:
5368 zig_unreachable();
5369 case ConstPtrSpecialRef:
5370 if (a->data.x_ptr.data.ref.pointee != b->data.x_ptr.data.ref.pointee)
5371 return false;
5372 return true;
5373 case ConstPtrSpecialBaseArray:
5374 if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val &&
5375 a->data.x_ptr.data.base_array.array_val->global_refs !=
5376 b->data.x_ptr.data.base_array.array_val->global_refs)
5377 {
5378 return false;
5379 }
5380 if (a->data.x_ptr.data.base_array.elem_index != b->data.x_ptr.data.base_array.elem_index)
5381 return false;
5382 if (a->data.x_ptr.data.base_array.is_cstr != b->data.x_ptr.data.base_array.is_cstr)
5383 return false;
5384 return true;
5385 case ConstPtrSpecialBaseStruct:
5386 if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val &&
5387 a->data.x_ptr.data.base_struct.struct_val->global_refs !=
5388 b->data.x_ptr.data.base_struct.struct_val->global_refs)
5389 {
5390 return false;
5391 }
5392 if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index)
5393 return false;
5394 return true;
5395 case ConstPtrSpecialHardCodedAddr:
5396 if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr)
5397 return false;
5398 return true;
5399 case ConstPtrSpecialDiscard:
5400 return true;
5401 case ConstPtrSpecialFunction:
5402 return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry;
5403 }
5404 zig_unreachable();
5450 return const_values_equal_ptr(a, b);
54055451 case TypeTableEntryIdArray:
54065452 zig_panic("TODO");
54075453 case TypeTableEntryIdStruct:
......@@ -5416,11 +5462,13 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
54165462 zig_panic("TODO");
54175463 case TypeTableEntryIdNull:
54185464 zig_panic("TODO");
5419 case TypeTableEntryIdMaybe:
5420 if (a->data.x_maybe == nullptr || b->data.x_maybe == nullptr) {
5421 return (a->data.x_maybe == nullptr && b->data.x_maybe == nullptr);
5465 case TypeTableEntryIdOptional:
5466 if (get_codegen_ptr_type(a->type) != nullptr)
5467 return const_values_equal_ptr(a, b);
5468 if (a->data.x_optional == nullptr || b->data.x_optional == nullptr) {
5469 return (a->data.x_optional == nullptr && b->data.x_optional == nullptr);
54225470 } else {
5423 return const_values_equal(a->data.x_maybe, b->data.x_maybe);
5471 return const_values_equal(a->data.x_optional, b->data.x_optional);
54245472 }
54255473 case TypeTableEntryIdErrorUnion:
54265474 zig_panic("TODO");
......@@ -5493,6 +5541,41 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *
54935541 }
54945542}
54955543
5544void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, TypeTableEntry *type_entry) {
5545 switch (const_val->data.x_ptr.special) {
5546 case ConstPtrSpecialInvalid:
5547 zig_unreachable();
5548 case ConstPtrSpecialRef:
5549 case ConstPtrSpecialBaseStruct:
5550 buf_appendf(buf, "*");
5551 render_const_value(g, buf, const_ptr_pointee(g, const_val));
5552 return;
5553 case ConstPtrSpecialBaseArray:
5554 if (const_val->data.x_ptr.data.base_array.is_cstr) {
5555 buf_appendf(buf, "*(c str lit)");
5556 return;
5557 } else {
5558 buf_appendf(buf, "*");
5559 render_const_value(g, buf, const_ptr_pointee(g, const_val));
5560 return;
5561 }
5562 case ConstPtrSpecialHardCodedAddr:
5563 buf_appendf(buf, "(*%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->data.pointer.child_type->name),
5564 const_val->data.x_ptr.data.hard_coded_addr.addr);
5565 return;
5566 case ConstPtrSpecialDiscard:
5567 buf_append_str(buf, "*_");
5568 return;
5569 case ConstPtrSpecialFunction:
5570 {
5571 FnTableEntry *fn_entry = const_val->data.x_ptr.data.fn.fn_entry;
5572 buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name));
5573 return;
5574 }
5575 }
5576 zig_unreachable();
5577}
5578
54965579void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
54975580 switch (const_val->special) {
54985581 case ConstValSpecialRuntime:
......@@ -5569,38 +5652,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
55695652 return;
55705653 }
55715654 case TypeTableEntryIdPointer:
5572 switch (const_val->data.x_ptr.special) {
5573 case ConstPtrSpecialInvalid:
5574 zig_unreachable();
5575 case ConstPtrSpecialRef:
5576 case ConstPtrSpecialBaseStruct:
5577 buf_appendf(buf, "&");
5578 render_const_value(g, buf, const_ptr_pointee(g, const_val));
5579 return;
5580 case ConstPtrSpecialBaseArray:
5581 if (const_val->data.x_ptr.data.base_array.is_cstr) {
5582 buf_appendf(buf, "&(c str lit)");
5583 return;
5584 } else {
5585 buf_appendf(buf, "&");
5586 render_const_value(g, buf, const_ptr_pointee(g, const_val));
5587 return;
5588 }
5589 case ConstPtrSpecialHardCodedAddr:
5590 buf_appendf(buf, "(&%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->data.pointer.child_type->name),
5591 const_val->data.x_ptr.data.hard_coded_addr.addr);
5592 return;
5593 case ConstPtrSpecialDiscard:
5594 buf_append_str(buf, "&_");
5595 return;
5596 case ConstPtrSpecialFunction:
5597 {
5598 FnTableEntry *fn_entry = const_val->data.x_ptr.data.fn.fn_entry;
5599 buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name));
5600 return;
5601 }
5602 }
5603 zig_unreachable();
5655 return render_const_val_ptr(g, buf, const_val, type_entry);
56045656 case TypeTableEntryIdBlock:
56055657 {
56065658 AstNode *node = const_val->data.x_block->source_node;
......@@ -5658,10 +5710,12 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
56585710 buf_appendf(buf, "undefined");
56595711 return;
56605712 }
5661 case TypeTableEntryIdMaybe:
5713 case TypeTableEntryIdOptional:
56625714 {
5663 if (const_val->data.x_maybe) {
5664 render_const_value(g, buf, const_val->data.x_maybe);
5715 if (get_codegen_ptr_type(const_val->type) != nullptr)
5716 return render_const_val_ptr(g, buf, const_val, type_entry->data.maybe.child_type);
5717 if (const_val->data.x_optional) {
5718 render_const_value(g, buf, const_val->data.x_optional);
56655719 } else {
56665720 buf_appendf(buf, "null");
56675721 }
......@@ -5767,7 +5821,7 @@ uint32_t type_id_hash(TypeId x) {
57675821 case TypeTableEntryIdComptimeInt:
57685822 case TypeTableEntryIdUndefined:
57695823 case TypeTableEntryIdNull:
5770 case TypeTableEntryIdMaybe:
5824 case TypeTableEntryIdOptional:
57715825 case TypeTableEntryIdErrorSet:
57725826 case TypeTableEntryIdEnum:
57735827 case TypeTableEntryIdUnion:
......@@ -5813,7 +5867,7 @@ bool type_id_eql(TypeId a, TypeId b) {
58135867 case TypeTableEntryIdComptimeInt:
58145868 case TypeTableEntryIdUndefined:
58155869 case TypeTableEntryIdNull:
5816 case TypeTableEntryIdMaybe:
5870 case TypeTableEntryIdOptional:
58175871 case TypeTableEntryIdPromise:
58185872 case TypeTableEntryIdErrorSet:
58195873 case TypeTableEntryIdEnum:
......@@ -5935,7 +5989,7 @@ static const TypeTableEntryId all_type_ids[] = {
59355989 TypeTableEntryIdComptimeInt,
59365990 TypeTableEntryIdUndefined,
59375991 TypeTableEntryIdNull,
5938 TypeTableEntryIdMaybe,
5992 TypeTableEntryIdOptional,
59395993 TypeTableEntryIdErrorUnion,
59405994 TypeTableEntryIdErrorSet,
59415995 TypeTableEntryIdEnum,
......@@ -5980,7 +6034,7 @@ size_t type_id_index(TypeTableEntry *entry) {
59806034 return 7;
59816035 case TypeTableEntryIdStruct:
59826036 if (entry->data.structure.is_slice)
5983 return 25;
6037 return 6;
59846038 return 8;
59856039 case TypeTableEntryIdComptimeFloat:
59866040 return 9;
......@@ -5990,7 +6044,7 @@ size_t type_id_index(TypeTableEntry *entry) {
59906044 return 11;
59916045 case TypeTableEntryIdNull:
59926046 return 12;
5993 case TypeTableEntryIdMaybe:
6047 case TypeTableEntryIdOptional:
59946048 return 13;
59956049 case TypeTableEntryIdErrorUnion:
59966050 return 14;
......@@ -6048,8 +6102,8 @@ const char *type_id_name(TypeTableEntryId id) {
60486102 return "Undefined";
60496103 case TypeTableEntryIdNull:
60506104 return "Null";
6051 case TypeTableEntryIdMaybe:
6052 return "Nullable";
6105 case TypeTableEntryIdOptional:
6106 return "Optional";
60536107 case TypeTableEntryIdErrorUnion:
60546108 return "ErrorUnion";
60556109 case TypeTableEntryIdErrorSet:
src/analyze.hpp+2
......@@ -70,6 +70,8 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name);
7070TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag);
7171TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag);
7272
73bool is_ref(TypeTableEntry *type_entry);
74bool is_array_ref(TypeTableEntry *type_entry);
7375bool is_container_ref(TypeTableEntry *type_entry);
7476void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
7577void scan_import(CodeGen *g, ImportTableEntry *import);
src/ast_render.cpp+11-3
......@@ -50,7 +50,7 @@ static const char *bin_op_str(BinOpType bin_op) {
5050 case BinOpTypeAssignBitXor: return "^=";
5151 case BinOpTypeAssignBitOr: return "|=";
5252 case BinOpTypeAssignMergeErrorSets: return "||=";
53 case BinOpTypeUnwrapMaybe: return "??";
53 case BinOpTypeUnwrapOptional: return "orelse";
5454 case BinOpTypeArrayCat: return "++";
5555 case BinOpTypeArrayMult: return "**";
5656 case BinOpTypeErrorUnion: return "!";
......@@ -66,8 +66,7 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
6666 case PrefixOpNegationWrap: return "-%";
6767 case PrefixOpBoolNot: return "!";
6868 case PrefixOpBinNot: return "~";
69 case PrefixOpMaybe: return "?";
70 case PrefixOpUnwrapMaybe: return "??";
69 case PrefixOpOptional: return "?";
7170 case PrefixOpAddrOf: return "&";
7271 }
7372 zig_unreachable();
......@@ -222,6 +221,8 @@ static const char *node_type_str(NodeType node_type) {
222221 return "FieldAccessExpr";
223222 case NodeTypePtrDeref:
224223 return "PtrDerefExpr";
224 case NodeTypeUnwrapOptional:
225 return "UnwrapOptional";
225226 case NodeTypeContainerDecl:
226227 return "ContainerDecl";
227228 case NodeTypeStructField:
......@@ -711,6 +712,13 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
711712 fprintf(ar->f, ".*");
712713 break;
713714 }
715 case NodeTypeUnwrapOptional:
716 {
717 AstNode *lhs = node->data.unwrap_optional.expr;
718 render_node_ungrouped(ar, lhs);
719 fprintf(ar->f, ".?");
720 break;
721 }
714722 case NodeTypeUndefinedLiteral:
715723 fprintf(ar->f, "undefined");
716724 break;
src/codegen.cpp+251-193
......@@ -869,7 +869,7 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
869869 return buf_create_from_str("exact division produced remainder");
870870 case PanicMsgIdSliceWidenRemainder:
871871 return buf_create_from_str("slice widening size mismatch");
872 case PanicMsgIdUnwrapMaybeFail:
872 case PanicMsgIdUnwrapOptionalFail:
873873 return buf_create_from_str("attempt to unwrap null");
874874 case PanicMsgIdUnreachable:
875875 return buf_create_from_str("reached unreachable code");
......@@ -879,6 +879,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
879879 return buf_create_from_str("incorrect alignment");
880880 case PanicMsgIdBadUnionField:
881881 return buf_create_from_str("access of inactive union field");
882 case PanicMsgIdBadEnumValue:
883 return buf_create_from_str("invalid enum value");
882884 }
883885 zig_unreachable();
884886}
......@@ -2497,7 +2499,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
24972499 assert(wanted_type->data.structure.is_slice);
24982500 assert(actual_type->id == TypeTableEntryIdArray);
24992501
2500 TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;
2502 TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
25012503 TypeTableEntry *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
25022504
25032505
......@@ -2543,6 +2545,29 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
25432545 return expr_val;
25442546 case CastOpBitCast:
25452547 return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
2548 case CastOpPtrOfArrayToSlice: {
2549 assert(cast_instruction->tmp_ptr);
2550 assert(actual_type->id == TypeTableEntryIdPointer);
2551 TypeTableEntry *array_type = actual_type->data.pointer.child_type;
2552 assert(array_type->id == TypeTableEntryIdArray);
2553
2554 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
2555 slice_ptr_index, "");
2556 LLVMValueRef indices[] = {
2557 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
2558 LLVMConstInt(g->builtin_types.entry_usize->type_ref, 0, false),
2559 };
2560 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, "");
2561 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
2562
2563 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
2564 slice_len_index, "");
2565 LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
2566 array_type->data.array.len, false);
2567 gen_store_untyped(g, len_value, len_field_ptr, 0, false);
2568
2569 return cast_instruction->tmp_ptr;
2570 }
25462571 }
25472572 zig_unreachable();
25482573}
......@@ -2678,7 +2703,7 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
26782703
26792704 switch (op_id) {
26802705 case IrUnOpInvalid:
2681 case IrUnOpMaybe:
2706 case IrUnOpOptional:
26822707 case IrUnOpDereference:
26832708 zig_unreachable();
26842709 case IrUnOpNegation:
......@@ -3249,7 +3274,7 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
32493274}
32503275
32513276static LLVMValueRef gen_non_null_bit(CodeGen *g, TypeTableEntry *maybe_type, LLVMValueRef maybe_handle) {
3252 assert(maybe_type->id == TypeTableEntryIdMaybe);
3277 assert(maybe_type->id == TypeTableEntryIdOptional);
32533278 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
32543279 if (child_type->zero_bits) {
32553280 return maybe_handle;
......@@ -3271,23 +3296,23 @@ static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable
32713296}
32723297
32733298static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
3274 IrInstructionUnwrapMaybe *instruction)
3299 IrInstructionUnwrapOptional *instruction)
32753300{
32763301 TypeTableEntry *ptr_type = instruction->value->value.type;
32773302 assert(ptr_type->id == TypeTableEntryIdPointer);
32783303 TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type;
3279 assert(maybe_type->id == TypeTableEntryIdMaybe);
3304 assert(maybe_type->id == TypeTableEntryIdOptional);
32803305 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
32813306 LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
32823307 LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
32833308 if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) {
32843309 LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle);
3285 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk");
3286 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeFail");
3310 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk");
3311 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail");
32873312 LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block);
32883313
32893314 LLVMPositionBuilderAtEnd(g->builder, fail_block);
3290 gen_safety_crash(g, PanicMsgIdUnwrapMaybeFail);
3315 gen_safety_crash(g, PanicMsgIdUnwrapOptionalFail);
32913316
32923317 LLVMPositionBuilderAtEnd(g->builder, ok_block);
32933318 }
......@@ -3432,34 +3457,112 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI
34323457 return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, "");
34333458}
34343459
3460static LLVMValueRef get_enum_tag_name_function(CodeGen *g, TypeTableEntry *enum_type) {
3461 assert(enum_type->id == TypeTableEntryIdEnum);
3462 if (enum_type->data.enumeration.name_function)
3463 return enum_type->data.enumeration.name_function;
3464
3465 TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, false, false,
3466 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
3467 TypeTableEntry *u8_slice_type = get_slice_type(g, u8_ptr_type);
3468 TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type;
3469
3470 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(u8_slice_type->type_ref, 0),
3471 &tag_int_type->type_ref, 1, false);
3472
3473 Buf *fn_name = get_mangled_name(g, buf_sprintf("__zig_tag_name_%s", buf_ptr(&enum_type->name)), false);
3474 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
3475 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
3476 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
3477 addLLVMFnAttr(fn_val, "nounwind");
3478 add_uwtable_attr(g, fn_val);
3479 if (g->build_mode == BuildModeDebug) {
3480 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
3481 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
3482 }
3483
3484 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
3485 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
3486 FnTableEntry *prev_cur_fn = g->cur_fn;
3487 LLVMValueRef prev_cur_fn_val = g->cur_fn_val;
3488
3489 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
3490 LLVMPositionBuilderAtEnd(g->builder, entry_block);
3491 ZigLLVMClearCurrentDebugLocation(g->builder);
3492 g->cur_fn = nullptr;
3493 g->cur_fn_val = fn_val;
3494
3495 size_t field_count = enum_type->data.enumeration.src_field_count;
3496 LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue");
3497 LLVMValueRef tag_int_value = LLVMGetParam(fn_val, 0);
3498 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count);
3499
3500
3501 TypeTableEntry *usize = g->builtin_types.entry_usize;
3502 LLVMValueRef array_ptr_indices[] = {
3503 LLVMConstNull(usize->type_ref),
3504 LLVMConstNull(usize->type_ref),
3505 };
3506
3507 for (size_t field_i = 0; field_i < field_count; field_i += 1) {
3508 Buf *name = enum_type->data.enumeration.fields[field_i].name;
3509 LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);
3510 LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
3511 LLVMSetInitializer(str_global, str_init);
3512 LLVMSetLinkage(str_global, LLVMPrivateLinkage);
3513 LLVMSetGlobalConstant(str_global, true);
3514 LLVMSetUnnamedAddr(str_global, true);
3515 LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init)));
3516
3517 LLVMValueRef fields[] = {
3518 LLVMConstGEP(str_global, array_ptr_indices, 2),
3519 LLVMConstInt(g->builtin_types.entry_usize->type_ref, buf_len(name), false),
3520 };
3521 LLVMValueRef slice_init_value = LLVMConstNamedStruct(u8_slice_type->type_ref, fields, 2);
3522
3523 LLVMValueRef slice_global = LLVMAddGlobal(g->module, LLVMTypeOf(slice_init_value), "");
3524 LLVMSetInitializer(slice_global, slice_init_value);
3525 LLVMSetLinkage(slice_global, LLVMPrivateLinkage);
3526 LLVMSetGlobalConstant(slice_global, true);
3527 LLVMSetUnnamedAddr(slice_global, true);
3528 LLVMSetAlignment(slice_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(slice_init_value)));
3529
3530 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "Name");
3531 LLVMValueRef this_tag_int_value = bigint_to_llvm_const(tag_int_type->type_ref,
3532 &enum_type->data.enumeration.fields[field_i].value);
3533 LLVMAddCase(switch_instr, this_tag_int_value, return_block);
3534
3535 LLVMPositionBuilderAtEnd(g->builder, return_block);
3536 LLVMBuildRet(g->builder, slice_global);
3537 }
3538
3539 LLVMPositionBuilderAtEnd(g->builder, bad_value_block);
3540 if (g->build_mode == BuildModeDebug || g->build_mode == BuildModeSafeRelease) {
3541 gen_safety_crash(g, PanicMsgIdBadEnumValue);
3542 } else {
3543 LLVMBuildUnreachable(g->builder);
3544 }
3545
3546 g->cur_fn = prev_cur_fn;
3547 g->cur_fn_val = prev_cur_fn_val;
3548 LLVMPositionBuilderAtEnd(g->builder, prev_block);
3549 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
3550
3551 enum_type->data.enumeration.name_function = fn_val;
3552 return fn_val;
3553}
3554
34353555static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable,
34363556 IrInstructionTagName *instruction)
34373557{
34383558 TypeTableEntry *enum_type = instruction->target->value.type;
34393559 assert(enum_type->id == TypeTableEntryIdEnum);
3440 assert(enum_type->data.enumeration.generate_name_table);
34413560
3442 TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type;
3443 LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target);
3444 if (ir_want_runtime_safety(g, &instruction->base)) {
3445 size_t field_count = enum_type->data.enumeration.src_field_count;
3446
3447 // if the field_count can't fit in the bits of the enum_type, then it can't possibly
3448 // be the wrong value
3449 BigInt field_bi;
3450 bigint_init_unsigned(&field_bi, field_count);
3451 if (bigint_fits_in_bits(&field_bi, tag_int_type->data.integral.bit_count, false)) {
3452 LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(enum_tag_value), field_count, false);
3453 add_bounds_check(g, enum_tag_value, LLVMIntEQ, nullptr, LLVMIntULT, end_val);
3454 }
3455 }
3561 LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type);
34563562
3457 LLVMValueRef indices[] = {
3458 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
3459 gen_widen_or_shorten(g, false, tag_int_type,
3460 g->builtin_types.entry_usize, enum_tag_value),
3461 };
3462 return LLVMBuildInBoundsGEP(g->builder, enum_type->data.enumeration.name_table, indices, 2, "");
3563 LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target);
3564 return ZigLLVMBuildCall(g->builder, enum_name_function, &enum_tag_value, 1,
3565 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
34633566}
34643567
34653568static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executable,
......@@ -3509,17 +3612,17 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
35093612 } else if (target_type->id == TypeTableEntryIdFn) {
35103613 align_bytes = target_type->data.fn.fn_type_id.alignment;
35113614 ptr_val = target_val;
3512 } else if (target_type->id == TypeTableEntryIdMaybe &&
3615 } else if (target_type->id == TypeTableEntryIdOptional &&
35133616 target_type->data.maybe.child_type->id == TypeTableEntryIdPointer)
35143617 {
35153618 align_bytes = target_type->data.maybe.child_type->data.pointer.alignment;
35163619 ptr_val = target_val;
3517 } else if (target_type->id == TypeTableEntryIdMaybe &&
3620 } else if (target_type->id == TypeTableEntryIdOptional &&
35183621 target_type->data.maybe.child_type->id == TypeTableEntryIdFn)
35193622 {
35203623 align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment;
35213624 ptr_val = target_val;
3522 } else if (target_type->id == TypeTableEntryIdMaybe &&
3625 } else if (target_type->id == TypeTableEntryIdOptional &&
35233626 target_type->data.maybe.child_type->id == TypeTableEntryIdPromise)
35243627 {
35253628 zig_panic("TODO audit this function");
......@@ -3621,7 +3724,7 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn
36213724 success_order, failure_order, instruction->is_weak);
36223725
36233726 TypeTableEntry *maybe_type = instruction->base.value.type;
3624 assert(maybe_type->id == TypeTableEntryIdMaybe);
3727 assert(maybe_type->id == TypeTableEntryIdOptional);
36253728 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
36263729
36273730 if (type_is_codegen_pointer(child_type)) {
......@@ -3730,7 +3833,6 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
37303833 } else {
37313834 end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false);
37323835 }
3733
37343836 if (want_runtime_safety) {
37353837 add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
37363838 if (instruction->end) {
......@@ -4008,10 +4110,10 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
40084110 }
40094111}
40104112
4011static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, IrInstructionMaybeWrap *instruction) {
4113static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, IrInstructionOptionalWrap *instruction) {
40124114 TypeTableEntry *wanted_type = instruction->base.value.type;
40134115
4014 assert(wanted_type->id == TypeTableEntryIdMaybe);
4116 assert(wanted_type->id == TypeTableEntryIdOptional);
40154117
40164118 TypeTableEntry *child_type = wanted_type->data.maybe.child_type;
40174119
......@@ -4540,7 +4642,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
45404642 case IrInstructionIdCheckSwitchProngs:
45414643 case IrInstructionIdCheckStatementIsVoid:
45424644 case IrInstructionIdTypeName:
4543 case IrInstructionIdCanImplicitCast:
45444645 case IrInstructionIdDeclRef:
45454646 case IrInstructionIdSwitchVar:
45464647 case IrInstructionIdOffsetOf:
......@@ -4593,8 +4694,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
45934694 return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
45944695 case IrInstructionIdTestNonNull:
45954696 return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction);
4596 case IrInstructionIdUnwrapMaybe:
4597 return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapMaybe *)instruction);
4697 case IrInstructionIdUnwrapOptional:
4698 return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapOptional *)instruction);
45984699 case IrInstructionIdClz:
45994700 return ir_render_clz(g, executable, (IrInstructionClz *)instruction);
46004701 case IrInstructionIdCtz:
......@@ -4635,8 +4736,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
46354736 return ir_render_unwrap_err_code(g, executable, (IrInstructionUnwrapErrCode *)instruction);
46364737 case IrInstructionIdUnwrapErrPayload:
46374738 return ir_render_unwrap_err_payload(g, executable, (IrInstructionUnwrapErrPayload *)instruction);
4638 case IrInstructionIdMaybeWrap:
4639 return ir_render_maybe_wrap(g, executable, (IrInstructionMaybeWrap *)instruction);
4739 case IrInstructionIdOptionalWrap:
4740 return ir_render_maybe_wrap(g, executable, (IrInstructionOptionalWrap *)instruction);
46404741 case IrInstructionIdErrWrapCode:
46414742 return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction);
46424743 case IrInstructionIdErrWrapPayload:
......@@ -4866,7 +4967,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
48664967 }
48674968 case TypeTableEntryIdPointer:
48684969 case TypeTableEntryIdFn:
4869 case TypeTableEntryIdMaybe:
4970 case TypeTableEntryIdOptional:
48704971 case TypeTableEntryIdPromise:
48714972 {
48724973 LLVMValueRef ptr_val = gen_const_val(g, const_val, "");
......@@ -4914,6 +5015,79 @@ static bool is_llvm_value_unnamed_type(TypeTableEntry *type_entry, LLVMValueRef
49145015 return LLVMTypeOf(val) != type_entry->type_ref;
49155016}
49165017
5018static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, const char *name) {
5019 render_const_val_global(g, const_val, name);
5020 switch (const_val->data.x_ptr.special) {
5021 case ConstPtrSpecialInvalid:
5022 case ConstPtrSpecialDiscard:
5023 zig_unreachable();
5024 case ConstPtrSpecialRef:
5025 {
5026 ConstExprValue *pointee = const_val->data.x_ptr.data.ref.pointee;
5027 render_const_val(g, pointee, "");
5028 render_const_val_global(g, pointee, "");
5029 ConstExprValue *other_val = pointee;
5030 const_val->global_refs->llvm_value = LLVMConstBitCast(other_val->global_refs->llvm_global, const_val->type->type_ref);
5031 render_const_val_global(g, const_val, "");
5032 return const_val->global_refs->llvm_value;
5033 }
5034 case ConstPtrSpecialBaseArray:
5035 {
5036 ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val;
5037 size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
5038 assert(array_const_val->type->id == TypeTableEntryIdArray);
5039 if (array_const_val->type->zero_bits) {
5040 // make this a null pointer
5041 TypeTableEntry *usize = g->builtin_types.entry_usize;
5042 const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
5043 const_val->type->type_ref);
5044 render_const_val_global(g, const_val, "");
5045 return const_val->global_refs->llvm_value;
5046 }
5047 LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val,
5048 elem_index);
5049 LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
5050 const_val->global_refs->llvm_value = ptr_val;
5051 render_const_val_global(g, const_val, "");
5052 return ptr_val;
5053 }
5054 case ConstPtrSpecialBaseStruct:
5055 {
5056 ConstExprValue *struct_const_val = const_val->data.x_ptr.data.base_struct.struct_val;
5057 assert(struct_const_val->type->id == TypeTableEntryIdStruct);
5058 if (struct_const_val->type->zero_bits) {
5059 // make this a null pointer
5060 TypeTableEntry *usize = g->builtin_types.entry_usize;
5061 const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
5062 const_val->type->type_ref);
5063 render_const_val_global(g, const_val, "");
5064 return const_val->global_refs->llvm_value;
5065 }
5066 size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index;
5067 size_t gen_field_index =
5068 struct_const_val->type->data.structure.fields[src_field_index].gen_index;
5069 LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val,
5070 gen_field_index);
5071 LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
5072 const_val->global_refs->llvm_value = ptr_val;
5073 render_const_val_global(g, const_val, "");
5074 return ptr_val;
5075 }
5076 case ConstPtrSpecialHardCodedAddr:
5077 {
5078 uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr;
5079 TypeTableEntry *usize = g->builtin_types.entry_usize;
5080 const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, addr_value, false),
5081 const_val->type->type_ref);
5082 render_const_val_global(g, const_val, "");
5083 return const_val->global_refs->llvm_value;
5084 }
5085 case ConstPtrSpecialFunction:
5086 return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref);
5087 }
5088 zig_unreachable();
5089}
5090
49175091static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) {
49185092 TypeTableEntry *type_entry = const_val->type;
49195093 assert(!type_entry->zero_bits);
......@@ -4958,23 +5132,19 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
49585132 } else {
49595133 return LLVMConstNull(LLVMInt1Type());
49605134 }
4961 case TypeTableEntryIdMaybe:
5135 case TypeTableEntryIdOptional:
49625136 {
49635137 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
49645138 if (child_type->zero_bits) {
4965 return LLVMConstInt(LLVMInt1Type(), const_val->data.x_maybe ? 1 : 0, false);
5139 return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false);
49665140 } else if (type_is_codegen_pointer(child_type)) {
4967 if (const_val->data.x_maybe) {
4968 return gen_const_val(g, const_val->data.x_maybe, "");
4969 } else {
4970 return LLVMConstNull(child_type->type_ref);
4971 }
5141 return gen_const_val_ptr(g, const_val, name);
49725142 } else {
49735143 LLVMValueRef child_val;
49745144 LLVMValueRef maybe_val;
49755145 bool make_unnamed_struct;
4976 if (const_val->data.x_maybe) {
4977 child_val = gen_const_val(g, const_val->data.x_maybe, "");
5146 if (const_val->data.x_optional) {
5147 child_val = gen_const_val(g, const_val->data.x_optional, "");
49785148 maybe_val = LLVMConstAllOnes(LLVMInt1Type());
49795149
49805150 make_unnamed_struct = is_llvm_value_unnamed_type(const_val->type, child_val);
......@@ -5164,78 +5334,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
51645334 assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst);
51655335 return fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry);
51665336 case TypeTableEntryIdPointer:
5167 {
5168 render_const_val_global(g, const_val, name);
5169 switch (const_val->data.x_ptr.special) {
5170 case ConstPtrSpecialInvalid:
5171 case ConstPtrSpecialDiscard:
5172 zig_unreachable();
5173 case ConstPtrSpecialRef:
5174 {
5175 ConstExprValue *pointee = const_val->data.x_ptr.data.ref.pointee;
5176 render_const_val(g, pointee, "");
5177 render_const_val_global(g, pointee, "");
5178 ConstExprValue *other_val = pointee;
5179 const_val->global_refs->llvm_value = LLVMConstBitCast(other_val->global_refs->llvm_global, const_val->type->type_ref);
5180 render_const_val_global(g, const_val, "");
5181 return const_val->global_refs->llvm_value;
5182 }
5183 case ConstPtrSpecialBaseArray:
5184 {
5185 ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val;
5186 size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
5187 assert(array_const_val->type->id == TypeTableEntryIdArray);
5188 if (array_const_val->type->zero_bits) {
5189 // make this a null pointer
5190 TypeTableEntry *usize = g->builtin_types.entry_usize;
5191 const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
5192 const_val->type->type_ref);
5193 render_const_val_global(g, const_val, "");
5194 return const_val->global_refs->llvm_value;
5195 }
5196 LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val,
5197 elem_index);
5198 LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
5199 const_val->global_refs->llvm_value = ptr_val;
5200 render_const_val_global(g, const_val, "");
5201 return ptr_val;
5202 }
5203 case ConstPtrSpecialBaseStruct:
5204 {
5205 ConstExprValue *struct_const_val = const_val->data.x_ptr.data.base_struct.struct_val;
5206 assert(struct_const_val->type->id == TypeTableEntryIdStruct);
5207 if (struct_const_val->type->zero_bits) {
5208 // make this a null pointer
5209 TypeTableEntry *usize = g->builtin_types.entry_usize;
5210 const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
5211 const_val->type->type_ref);
5212 render_const_val_global(g, const_val, "");
5213 return const_val->global_refs->llvm_value;
5214 }
5215 size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index;
5216 size_t gen_field_index =
5217 struct_const_val->type->data.structure.fields[src_field_index].gen_index;
5218 LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val,
5219 gen_field_index);
5220 LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
5221 const_val->global_refs->llvm_value = ptr_val;
5222 render_const_val_global(g, const_val, "");
5223 return ptr_val;
5224 }
5225 case ConstPtrSpecialHardCodedAddr:
5226 {
5227 uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr;
5228 TypeTableEntry *usize = g->builtin_types.entry_usize;
5229 const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, addr_value, false),
5230 const_val->type->type_ref);
5231 render_const_val_global(g, const_val, "");
5232 return const_val->global_refs->llvm_value;
5233 }
5234 case ConstPtrSpecialFunction:
5235 return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref);
5236 }
5237 }
5238 zig_unreachable();
5337 return gen_const_val_ptr(g, const_val, name);
52395338 case TypeTableEntryIdErrorUnion:
52405339 {
52415340 TypeTableEntry *payload_type = type_entry->data.error_union.payload_type;
......@@ -5367,55 +5466,6 @@ static void generate_error_name_table(CodeGen *g) {
53675466 LLVMSetAlignment(g->err_name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(err_name_table_init)));
53685467}
53695468
5370static void generate_enum_name_tables(CodeGen *g) {
5371 TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
5372 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
5373 TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
5374
5375 TypeTableEntry *usize = g->builtin_types.entry_usize;
5376 LLVMValueRef array_ptr_indices[] = {
5377 LLVMConstNull(usize->type_ref),
5378 LLVMConstNull(usize->type_ref),
5379 };
5380
5381
5382 for (size_t enum_i = 0; enum_i < g->name_table_enums.length; enum_i += 1) {
5383 TypeTableEntry *enum_type = g->name_table_enums.at(enum_i);
5384 assert(enum_type->id == TypeTableEntryIdEnum);
5385
5386 size_t field_count = enum_type->data.enumeration.src_field_count;
5387 LLVMValueRef *values = allocate<LLVMValueRef>(field_count);
5388 for (size_t field_i = 0; field_i < field_count; field_i += 1) {
5389 Buf *name = enum_type->data.enumeration.fields[field_i].name;
5390
5391 LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);
5392 LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
5393 LLVMSetInitializer(str_global, str_init);
5394 LLVMSetLinkage(str_global, LLVMPrivateLinkage);
5395 LLVMSetGlobalConstant(str_global, true);
5396 LLVMSetUnnamedAddr(str_global, true);
5397 LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init)));
5398
5399 LLVMValueRef fields[] = {
5400 LLVMConstGEP(str_global, array_ptr_indices, 2),
5401 LLVMConstInt(g->builtin_types.entry_usize->type_ref, buf_len(name), false),
5402 };
5403 values[field_i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2);
5404 }
5405
5406 LLVMValueRef name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)field_count);
5407
5408 Buf *table_name = get_mangled_name(g, buf_sprintf("%s_name_table", buf_ptr(&enum_type->name)), false);
5409 LLVMValueRef name_table = LLVMAddGlobal(g->module, LLVMTypeOf(name_table_init), buf_ptr(table_name));
5410 LLVMSetInitializer(name_table, name_table_init);
5411 LLVMSetLinkage(name_table, LLVMPrivateLinkage);
5412 LLVMSetGlobalConstant(name_table, true);
5413 LLVMSetUnnamedAddr(name_table, true);
5414 LLVMSetAlignment(name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(name_table_init)));
5415 enum_type->data.enumeration.name_table = name_table;
5416 }
5417}
5418
54195469static void build_all_basic_blocks(CodeGen *g, FnTableEntry *fn) {
54205470 IrExecutable *executable = &fn->analyzed_executable;
54215471 assert(executable->basic_block_list.length > 0);
......@@ -5512,7 +5562,6 @@ static void do_code_gen(CodeGen *g) {
55125562 }
55135563
55145564 generate_error_name_table(g);
5515 generate_enum_name_tables(g);
55165565
55175566 // Generate module level variables
55185567 for (size_t i = 0; i < g->global_vars.length; i += 1) {
......@@ -5651,8 +5700,8 @@ static void do_code_gen(CodeGen *g) {
56515700 } else if (instruction->id == IrInstructionIdSlice) {
56525701 IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction;
56535702 slot = &slice_instruction->tmp_ptr;
5654 } else if (instruction->id == IrInstructionIdMaybeWrap) {
5655 IrInstructionMaybeWrap *maybe_wrap_instruction = (IrInstructionMaybeWrap *)instruction;
5703 } else if (instruction->id == IrInstructionIdOptionalWrap) {
5704 IrInstructionOptionalWrap *maybe_wrap_instruction = (IrInstructionOptionalWrap *)instruction;
56565705 slot = &maybe_wrap_instruction->tmp_ptr;
56575706 } else if (instruction->id == IrInstructionIdErrWrapPayload) {
56585707 IrInstructionErrWrapPayload *err_wrap_payload_instruction = (IrInstructionErrWrapPayload *)instruction;
......@@ -6192,7 +6241,6 @@ static void define_builtin_fns(CodeGen *g) {
61926241 create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1);
61936242 create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1);
61946243 create_builtin_fn(g, BuiltinFnIdTypeName, "typeName", 1);
6195 create_builtin_fn(g, BuiltinFnIdCanImplicitCast, "canImplicitCast", 2);
61966244 create_builtin_fn(g, BuiltinFnIdEmbedFile, "embedFile", 1);
61976245 create_builtin_fn(g, BuiltinFnIdCmpxchgWeak, "cmpxchgWeak", 6);
61986246 create_builtin_fn(g, BuiltinFnIdCmpxchgStrong, "cmpxchgStrong", 6);
......@@ -6250,13 +6298,7 @@ static const char *build_mode_to_str(BuildMode build_mode) {
62506298 zig_unreachable();
62516299}
62526300
6253static void define_builtin_compile_vars(CodeGen *g) {
6254 if (g->std_package == nullptr)
6255 return;
6256
6257 const char *builtin_zig_basename = "builtin.zig";
6258 Buf *builtin_zig_path = buf_alloc();
6259 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
6301Buf *codegen_generate_builtin_source(CodeGen *g) {
62606302 Buf *contents = buf_alloc();
62616303
62626304 // Modifications to this struct must be coordinated with code that does anything with
......@@ -6396,7 +6438,6 @@ static void define_builtin_compile_vars(CodeGen *g) {
63966438 const TypeTableEntryId id = type_id_at_index(i);
63976439 buf_appendf(contents, " %s,\n", type_id_name(id));
63986440 }
6399 buf_appendf(contents, " Slice,\n");
64006441 buf_appendf(contents, "};\n\n");
64016442 }
64026443 {
......@@ -6409,14 +6450,13 @@ static void define_builtin_compile_vars(CodeGen *g) {
64096450 " Int: Int,\n"
64106451 " Float: Float,\n"
64116452 " Pointer: Pointer,\n"
6412 " Slice: Slice,\n"
64136453 " Array: Array,\n"
64146454 " Struct: Struct,\n"
64156455 " ComptimeFloat: void,\n"
64166456 " ComptimeInt: void,\n"
64176457 " Undefined: void,\n"
64186458 " Null: void,\n"
6419 " Nullable: Nullable,\n"
6459 " Optional: Optional,\n"
64206460 " ErrorUnion: ErrorUnion,\n"
64216461 " ErrorSet: ErrorSet,\n"
64226462 " Enum: Enum,\n"
......@@ -6439,13 +6479,18 @@ static void define_builtin_compile_vars(CodeGen *g) {
64396479 " };\n"
64406480 "\n"
64416481 " pub const Pointer = struct {\n"
6482 " size: Size,\n"
64426483 " is_const: bool,\n"
64436484 " is_volatile: bool,\n"
64446485 " alignment: u32,\n"
64456486 " child: type,\n"
6446 " };\n"
64476487 "\n"
6448 " pub const Slice = Pointer;\n"
6488 " pub const Size = enum {\n"
6489 " One,\n"
6490 " Many,\n"
6491 " Slice,\n"
6492 " };\n"
6493 " };\n"
64496494 "\n"
64506495 " pub const Array = struct {\n"
64516496 " len: usize,\n"
......@@ -6470,7 +6515,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
64706515 " defs: []Definition,\n"
64716516 " };\n"
64726517 "\n"
6473 " pub const Nullable = struct {\n"
6518 " pub const Optional = struct {\n"
64746519 " child: type,\n"
64756520 " };\n"
64766521 "\n"
......@@ -6619,6 +6664,19 @@ static void define_builtin_compile_vars(CodeGen *g) {
66196664
66206665 buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n");
66216666
6667
6668 return contents;
6669}
6670
6671static void define_builtin_compile_vars(CodeGen *g) {
6672 if (g->std_package == nullptr)
6673 return;
6674
6675 const char *builtin_zig_basename = "builtin.zig";
6676 Buf *builtin_zig_path = buf_alloc();
6677 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
6678
6679 Buf *contents = codegen_generate_builtin_source(g);
66226680 ensure_cache_dir(g);
66236681 os_write_file(builtin_zig_path, contents);
66246682
......@@ -7032,7 +7090,7 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry
70327090 case TypeTableEntryIdArray:
70337091 prepend_c_type_to_decl_list(g, gen_h, type_entry->data.array.child_type);
70347092 return;
7035 case TypeTableEntryIdMaybe:
7093 case TypeTableEntryIdOptional:
70367094 prepend_c_type_to_decl_list(g, gen_h, type_entry->data.maybe.child_type);
70377095 return;
70387096 case TypeTableEntryIdFn:
......@@ -7121,7 +7179,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
71217179 buf_appendf(out_buf, "%s%s *", const_str, buf_ptr(&child_buf));
71227180 break;
71237181 }
7124 case TypeTableEntryIdMaybe:
7182 case TypeTableEntryIdOptional:
71257183 {
71267184 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
71277185 if (child_type->zero_bits) {
......@@ -7335,7 +7393,7 @@ static void gen_h_file(CodeGen *g) {
73357393 case TypeTableEntryIdBlock:
73367394 case TypeTableEntryIdBoundFn:
73377395 case TypeTableEntryIdArgTuple:
7338 case TypeTableEntryIdMaybe:
7396 case TypeTableEntryIdOptional:
73397397 case TypeTableEntryIdFn:
73407398 case TypeTableEntryIdPromise:
73417399 zig_unreachable();
src/codegen.hpp+2
......@@ -59,5 +59,7 @@ void codegen_add_object(CodeGen *g, Buf *object_path);
5959
6060void codegen_translate_c(CodeGen *g, Buf *path);
6161
62Buf *codegen_generate_builtin_source(CodeGen *g);
63
6264
6365#endif
src/ir.cpp+603-453
......@@ -47,7 +47,7 @@ enum ConstCastResultId {
4747 ConstCastResultIdErrSetGlobal,
4848 ConstCastResultIdPointerChild,
4949 ConstCastResultIdSliceChild,
50 ConstCastResultIdNullableChild,
50 ConstCastResultIdOptionalChild,
5151 ConstCastResultIdErrorUnionPayload,
5252 ConstCastResultIdErrorUnionErrorSet,
5353 ConstCastResultIdFnAlign,
......@@ -62,6 +62,7 @@ enum ConstCastResultId {
6262 ConstCastResultIdType,
6363 ConstCastResultIdUnresolvedInferredErrSet,
6464 ConstCastResultIdAsyncAllocatorType,
65 ConstCastResultIdNullWrapPtr,
6566};
6667
6768struct ConstCastErrSetMismatch {
......@@ -85,11 +86,12 @@ struct ConstCastOnly {
8586 ConstCastErrSetMismatch error_set;
8687 ConstCastOnly *pointer_child;
8788 ConstCastOnly *slice_child;
88 ConstCastOnly *nullable_child;
89 ConstCastOnly *optional_child;
8990 ConstCastOnly *error_union_payload;
9091 ConstCastOnly *error_union_error_set;
9192 ConstCastOnly *return_type;
9293 ConstCastOnly *async_allocator_type;
94 ConstCastOnly *null_wrap_ptr_child;
9395 ConstCastArg fn_arg;
9496 ConstCastArgNoAlias arg_no_alias;
9597 } data;
......@@ -108,9 +110,10 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
108110static TypeTableEntry *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op);
109111static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval);
110112static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, uint32_t new_align);
113static TypeTableEntry *adjust_slice_align(CodeGen *g, TypeTableEntry *slice_type, uint32_t new_align);
111114
112115ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
113 assert(const_val->type->id == TypeTableEntryIdPointer);
116 assert(get_codegen_ptr_type(const_val->type) != nullptr);
114117 assert(const_val->special == ConstValSpecialStatic);
115118 switch (const_val->data.x_ptr.special) {
116119 case ConstPtrSpecialInvalid:
......@@ -369,8 +372,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNonNull *) {
369372 return IrInstructionIdTestNonNull;
370373}
371374
372static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapMaybe *) {
373 return IrInstructionIdUnwrapMaybe;
375static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapOptional *) {
376 return IrInstructionIdUnwrapOptional;
374377}
375378
376379static constexpr IrInstructionId ir_instruction_id(IrInstructionClz *) {
......@@ -521,8 +524,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrPayload
521524 return IrInstructionIdUnwrapErrPayload;
522525}
523526
524static constexpr IrInstructionId ir_instruction_id(IrInstructionMaybeWrap *) {
525 return IrInstructionIdMaybeWrap;
527static constexpr IrInstructionId ir_instruction_id(IrInstructionOptionalWrap *) {
528 return IrInstructionIdOptionalWrap;
526529}
527530
528531static constexpr IrInstructionId ir_instruction_id(IrInstructionErrWrapPayload *) {
......@@ -585,10 +588,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeName *) {
585588 return IrInstructionIdTypeName;
586589}
587590
588static constexpr IrInstructionId ir_instruction_id(IrInstructionCanImplicitCast *) {
589 return IrInstructionIdCanImplicitCast;
590}
591
592591static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclRef *) {
593592 return IrInstructionIdDeclRef;
594593}
......@@ -1572,7 +1571,7 @@ static IrInstruction *ir_build_test_nonnull_from(IrBuilder *irb, IrInstruction *
15721571static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value,
15731572 bool safety_check_on)
15741573{
1575 IrInstructionUnwrapMaybe *instruction = ir_build_instruction<IrInstructionUnwrapMaybe>(irb, scope, source_node);
1574 IrInstructionUnwrapOptional *instruction = ir_build_instruction<IrInstructionUnwrapOptional>(irb, scope, source_node);
15761575 instruction->value = value;
15771576 instruction->safety_check_on = safety_check_on;
15781577
......@@ -1591,7 +1590,7 @@ static IrInstruction *ir_build_unwrap_maybe_from(IrBuilder *irb, IrInstruction *
15911590}
15921591
15931592static IrInstruction *ir_build_maybe_wrap(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
1594 IrInstructionMaybeWrap *instruction = ir_build_instruction<IrInstructionMaybeWrap>(irb, scope, source_node);
1593 IrInstructionOptionalWrap *instruction = ir_build_instruction<IrInstructionOptionalWrap>(irb, scope, source_node);
15951594 instruction->value = value;
15961595
15971596 ir_ref_instruction(value, irb->current_basic_block);
......@@ -2348,20 +2347,6 @@ static IrInstruction *ir_build_type_name(IrBuilder *irb, Scope *scope, AstNode *
23482347 return &instruction->base;
23492348}
23502349
2351static IrInstruction *ir_build_can_implicit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
2352 IrInstruction *type_value, IrInstruction *target_value)
2353{
2354 IrInstructionCanImplicitCast *instruction = ir_build_instruction<IrInstructionCanImplicitCast>(
2355 irb, scope, source_node);
2356 instruction->type_value = type_value;
2357 instruction->target_value = target_value;
2358
2359 ir_ref_instruction(type_value, irb->current_basic_block);
2360 ir_ref_instruction(target_value, irb->current_basic_block);
2361
2362 return &instruction->base;
2363}
2364
23652350static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node,
23662351 Tld *tld, LVal lval)
23672352{
......@@ -2511,9 +2496,9 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s
25112496 return &instruction->base;
25122497}
25132498
2514static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstructionErrorReturnTrace::Nullable nullable) {
2499static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstructionErrorReturnTrace::Optional optional) {
25152500 IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node);
2516 instruction->nullable = nullable;
2501 instruction->optional = optional;
25172502
25182503 return &instruction->base;
25192504}
......@@ -3310,9 +3295,9 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As
33103295 is_comptime = ir_build_test_comptime(irb, parent_scope, node, is_non_null);
33113296 }
33123297
3313 IrBasicBlock *ok_block = ir_create_basic_block(irb, parent_scope, "MaybeNonNull");
3314 IrBasicBlock *null_block = ir_create_basic_block(irb, parent_scope, "MaybeNull");
3315 IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "MaybeEnd");
3298 IrBasicBlock *ok_block = ir_create_basic_block(irb, parent_scope, "OptionalNonNull");
3299 IrBasicBlock *null_block = ir_create_basic_block(irb, parent_scope, "OptionalNull");
3300 IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "OptionalEnd");
33163301 ir_build_cond_br(irb, parent_scope, node, is_non_null, ok_block, null_block, is_comptime);
33173302
33183303 ir_set_cursor_at_end_and_append_block(irb, null_block);
......@@ -3441,7 +3426,7 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
34413426 return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult);
34423427 case BinOpTypeMergeErrorSets:
34433428 return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets);
3444 case BinOpTypeUnwrapMaybe:
3429 case BinOpTypeUnwrapOptional:
34453430 return ir_gen_maybe_ok_or(irb, scope, node);
34463431 case BinOpTypeErrorUnion:
34473432 return ir_gen_error_union(irb, scope, node);
......@@ -4132,21 +4117,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41324117 IrInstruction *type_name = ir_build_type_name(irb, scope, node, arg0_value);
41334118 return ir_lval_wrap(irb, scope, type_name, lval);
41344119 }
4135 case BuiltinFnIdCanImplicitCast:
4136 {
4137 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4138 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4139 if (arg0_value == irb->codegen->invalid_instruction)
4140 return arg0_value;
4141
4142 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4143 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4144 if (arg1_value == irb->codegen->invalid_instruction)
4145 return arg1_value;
4146
4147 IrInstruction *can_implicit_cast = ir_build_can_implicit_cast(irb, scope, node, arg0_value, arg1_value);
4148 return ir_lval_wrap(irb, scope, can_implicit_cast, lval);
4149 }
41504120 case BuiltinFnIdPanic:
41514121 {
41524122 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -4620,11 +4590,8 @@ static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *
46204590
46214591static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode *node) {
46224592 assert(node->type == NodeTypePointerType);
4623 // The null check here is for C imports which don't set a token on the AST node. We could potentially
4624 // update that code to create a fake token and then remove this check.
4625 PtrLen ptr_len = (node->data.pointer_type.star_token != nullptr &&
4626 (node->data.pointer_type.star_token->id == TokenIdStar ||
4627 node->data.pointer_type.star_token->id == TokenIdStarStar)) ? PtrLenSingle : PtrLenUnknown;
4593 PtrLen ptr_len = (node->data.pointer_type.star_token->id == TokenIdStar ||
4594 node->data.pointer_type.star_token->id == TokenIdStarStar) ? PtrLenSingle : PtrLenUnknown;
46284595 bool is_const = node->data.pointer_type.is_const;
46294596 bool is_volatile = node->data.pointer_type.is_volatile;
46304597 AstNode *expr_node = node->data.pointer_type.op_expr;
......@@ -4694,21 +4661,6 @@ static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode
46944661 return ir_build_load_ptr(irb, scope, source_node, payload_ptr);
46954662}
46964663
4697static IrInstruction *ir_gen_maybe_assert_ok(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
4698 assert(node->type == NodeTypePrefixOpExpr);
4699 AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
4700
4701 IrInstruction *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR);
4702 if (maybe_ptr == irb->codegen->invalid_instruction)
4703 return irb->codegen->invalid_instruction;
4704
4705 IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_ptr, true);
4706 if (lval.is_ptr)
4707 return unwrapped_ptr;
4708
4709 return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
4710}
4711
47124664static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *node) {
47134665 assert(node->type == NodeTypePrefixOpExpr);
47144666 AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
......@@ -4736,10 +4688,8 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
47364688 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval);
47374689 case PrefixOpNegationWrap:
47384690 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval);
4739 case PrefixOpMaybe:
4740 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe), lval);
4741 case PrefixOpUnwrapMaybe:
4742 return ir_gen_maybe_assert_ok(irb, scope, node, lval);
4691 case PrefixOpOptional:
4692 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval);
47434693 case PrefixOpAddrOf: {
47444694 AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
47454695 return ir_lval_wrap(irb, scope, ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR), lval);
......@@ -5403,9 +5353,9 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no
54035353 IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr);
54045354 IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_val);
54055355
5406 IrBasicBlock *then_block = ir_create_basic_block(irb, scope, "MaybeThen");
5407 IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "MaybeElse");
5408 IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "MaybeEndIf");
5356 IrBasicBlock *then_block = ir_create_basic_block(irb, scope, "OptionalThen");
5357 IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "OptionalElse");
5358 IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "OptionalEndIf");
54095359
54105360 IrInstruction *is_comptime;
54115361 if (ir_should_inline(irb->exec, scope)) {
......@@ -6574,7 +6524,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
65746524 return ir_build_load_ptr(irb, scope, node, ptr_instruction);
65756525 }
65766526 case NodeTypePtrDeref: {
6577 assert(node->type == NodeTypePtrDeref);
65786527 AstNode *expr_node = node->data.ptr_deref_expr.target;
65796528 IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval);
65806529 if (value == irb->codegen->invalid_instruction)
......@@ -6582,6 +6531,19 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
65826531
65836532 return ir_build_un_op(irb, scope, node, IrUnOpDereference, value);
65846533 }
6534 case NodeTypeUnwrapOptional: {
6535 AstNode *expr_node = node->data.unwrap_optional.expr;
6536
6537 IrInstruction *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR);
6538 if (maybe_ptr == irb->codegen->invalid_instruction)
6539 return irb->codegen->invalid_instruction;
6540
6541 IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_ptr, true);
6542 if (lval.is_ptr)
6543 return unwrapped_ptr;
6544
6545 return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
6546 }
65856547 case NodeTypeThisLiteral:
65866548 return ir_lval_wrap(irb, scope, ir_gen_this_literal(irb, scope, node), lval);
65876549 case NodeTypeBoolLiteral:
......@@ -7552,7 +7514,7 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
75527514 }
75537515 } else if (const_val_fits_in_num_lit(const_val, other_type)) {
75547516 return true;
7555 } else if (other_type->id == TypeTableEntryIdMaybe) {
7517 } else if (other_type->id == TypeTableEntryIdOptional) {
75567518 TypeTableEntry *child_type = other_type->data.maybe.child_type;
75577519 if (const_val_fits_in_num_lit(const_val, child_type)) {
75587520 return true;
......@@ -7685,27 +7647,44 @@ static TypeTableEntry *get_error_set_intersection(IrAnalyze *ira, TypeTableEntry
76857647}
76867648
76877649
7688static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry *expected_type,
7689 TypeTableEntry *actual_type, AstNode *source_node)
7650static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry *wanted_type,
7651 TypeTableEntry *actual_type, AstNode *source_node, bool wanted_is_mutable)
76907652{
76917653 CodeGen *g = ira->codegen;
76927654 ConstCastOnly result = {};
76937655 result.id = ConstCastResultIdOk;
76947656
7695 if (expected_type == actual_type)
7657 if (wanted_type == actual_type)
7658 return result;
7659
7660 // * and [*] can do a const-cast-only to ?* and ?[*], respectively
7661 // but not if there is a mutable parent pointer
7662 if (!wanted_is_mutable && wanted_type->id == TypeTableEntryIdOptional &&
7663 wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer &&
7664 actual_type->id == TypeTableEntryIdPointer)
7665 {
7666 ConstCastOnly child = types_match_const_cast_only(ira,
7667 wanted_type->data.maybe.child_type, actual_type, source_node, wanted_is_mutable);
7668 if (child.id != ConstCastResultIdOk) {
7669 result.id = ConstCastResultIdNullWrapPtr;
7670 result.data.null_wrap_ptr_child = allocate_nonzero<ConstCastOnly>(1);
7671 *result.data.null_wrap_ptr_child = child;
7672 }
76967673 return result;
7674 }
76977675
76987676 // pointer const
7699 if (expected_type->id == TypeTableEntryIdPointer &&
7677 if (wanted_type->id == TypeTableEntryIdPointer &&
77007678 actual_type->id == TypeTableEntryIdPointer &&
7701 (actual_type->data.pointer.ptr_len == expected_type->data.pointer.ptr_len) &&
7702 (!actual_type->data.pointer.is_const || expected_type->data.pointer.is_const) &&
7703 (!actual_type->data.pointer.is_volatile || expected_type->data.pointer.is_volatile) &&
7704 actual_type->data.pointer.bit_offset == expected_type->data.pointer.bit_offset &&
7705 actual_type->data.pointer.unaligned_bit_count == expected_type->data.pointer.unaligned_bit_count &&
7706 actual_type->data.pointer.alignment >= expected_type->data.pointer.alignment)
7679 (actual_type->data.pointer.ptr_len == wanted_type->data.pointer.ptr_len) &&
7680 (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) &&
7681 (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile) &&
7682 actual_type->data.pointer.bit_offset == wanted_type->data.pointer.bit_offset &&
7683 actual_type->data.pointer.unaligned_bit_count == wanted_type->data.pointer.unaligned_bit_count &&
7684 actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment)
77077685 {
7708 ConstCastOnly child = types_match_const_cast_only(ira, expected_type->data.pointer.child_type, actual_type->data.pointer.child_type, source_node);
7686 ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
7687 actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const);
77097688 if (child.id != ConstCastResultIdOk) {
77107689 result.id = ConstCastResultIdPointerChild;
77117690 result.data.pointer_child = allocate_nonzero<ConstCastOnly>(1);
......@@ -7715,17 +7694,17 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
77157694 }
77167695
77177696 // slice const
7718 if (is_slice(expected_type) && is_slice(actual_type)) {
7697 if (is_slice(wanted_type) && is_slice(actual_type)) {
77197698 TypeTableEntry *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index].type_entry;
7720 TypeTableEntry *expected_ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry;
7721 if ((!actual_ptr_type->data.pointer.is_const || expected_ptr_type->data.pointer.is_const) &&
7722 (!actual_ptr_type->data.pointer.is_volatile || expected_ptr_type->data.pointer.is_volatile) &&
7723 actual_ptr_type->data.pointer.bit_offset == expected_ptr_type->data.pointer.bit_offset &&
7724 actual_ptr_type->data.pointer.unaligned_bit_count == expected_ptr_type->data.pointer.unaligned_bit_count &&
7725 actual_ptr_type->data.pointer.alignment >= expected_ptr_type->data.pointer.alignment)
7699 TypeTableEntry *wanted_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
7700 if ((!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) &&
7701 (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) &&
7702 actual_ptr_type->data.pointer.bit_offset == wanted_ptr_type->data.pointer.bit_offset &&
7703 actual_ptr_type->data.pointer.unaligned_bit_count == wanted_ptr_type->data.pointer.unaligned_bit_count &&
7704 actual_ptr_type->data.pointer.alignment >= wanted_ptr_type->data.pointer.alignment)
77267705 {
7727 ConstCastOnly child = types_match_const_cast_only(ira, expected_ptr_type->data.pointer.child_type,
7728 actual_ptr_type->data.pointer.child_type, source_node);
7706 ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type,
7707 actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const);
77297708 if (child.id != ConstCastResultIdOk) {
77307709 result.id = ConstCastResultIdSliceChild;
77317710 result.data.slice_child = allocate_nonzero<ConstCastOnly>(1);
......@@ -7736,26 +7715,29 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
77367715 }
77377716
77387717 // maybe
7739 if (expected_type->id == TypeTableEntryIdMaybe && actual_type->id == TypeTableEntryIdMaybe) {
7740 ConstCastOnly child = types_match_const_cast_only(ira, expected_type->data.maybe.child_type, actual_type->data.maybe.child_type, source_node);
7718 if (wanted_type->id == TypeTableEntryIdOptional && actual_type->id == TypeTableEntryIdOptional) {
7719 ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.maybe.child_type,
7720 actual_type->data.maybe.child_type, source_node, wanted_is_mutable);
77417721 if (child.id != ConstCastResultIdOk) {
7742 result.id = ConstCastResultIdNullableChild;
7743 result.data.nullable_child = allocate_nonzero<ConstCastOnly>(1);
7744 *result.data.nullable_child = child;
7722 result.id = ConstCastResultIdOptionalChild;
7723 result.data.optional_child = allocate_nonzero<ConstCastOnly>(1);
7724 *result.data.optional_child = child;
77457725 }
77467726 return result;
77477727 }
77487728
77497729 // error union
7750 if (expected_type->id == TypeTableEntryIdErrorUnion && actual_type->id == TypeTableEntryIdErrorUnion) {
7751 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);
7730 if (wanted_type->id == TypeTableEntryIdErrorUnion && actual_type->id == TypeTableEntryIdErrorUnion) {
7731 ConstCastOnly payload_child = types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type,
7732 actual_type->data.error_union.payload_type, source_node, wanted_is_mutable);
77527733 if (payload_child.id != ConstCastResultIdOk) {
77537734 result.id = ConstCastResultIdErrorUnionPayload;
77547735 result.data.error_union_payload = allocate_nonzero<ConstCastOnly>(1);
77557736 *result.data.error_union_payload = payload_child;
77567737 return result;
77577738 }
7758 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);
7739 ConstCastOnly error_set_child = types_match_const_cast_only(ira, wanted_type->data.error_union.err_set_type,
7740 actual_type->data.error_union.err_set_type, source_node, wanted_is_mutable);
77597741 if (error_set_child.id != ConstCastResultIdOk) {
77607742 result.id = ConstCastResultIdErrorUnionErrorSet;
77617743 result.data.error_union_error_set = allocate_nonzero<ConstCastOnly>(1);
......@@ -7766,9 +7748,9 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
77667748 }
77677749
77687750 // error set
7769 if (expected_type->id == TypeTableEntryIdErrorSet && actual_type->id == TypeTableEntryIdErrorSet) {
7751 if (wanted_type->id == TypeTableEntryIdErrorSet && actual_type->id == TypeTableEntryIdErrorSet) {
77707752 TypeTableEntry *contained_set = actual_type;
7771 TypeTableEntry *container_set = expected_type;
7753 TypeTableEntry *container_set = wanted_type;
77727754
77737755 // if the container set is inferred, then this will always work.
77747756 if (container_set->data.error_set.infer_fn != nullptr) {
......@@ -7809,36 +7791,37 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
78097791 return result;
78107792 }
78117793
7812 if (expected_type == ira->codegen->builtin_types.entry_promise &&
7794 if (wanted_type == ira->codegen->builtin_types.entry_promise &&
78137795 actual_type->id == TypeTableEntryIdPromise)
78147796 {
78157797 return result;
78167798 }
78177799
78187800 // fn
7819 if (expected_type->id == TypeTableEntryIdFn &&
7801 if (wanted_type->id == TypeTableEntryIdFn &&
78207802 actual_type->id == TypeTableEntryIdFn)
78217803 {
7822 if (expected_type->data.fn.fn_type_id.alignment > actual_type->data.fn.fn_type_id.alignment) {
7804 if (wanted_type->data.fn.fn_type_id.alignment > actual_type->data.fn.fn_type_id.alignment) {
78237805 result.id = ConstCastResultIdFnAlign;
78247806 return result;
78257807 }
7826 if (expected_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) {
7808 if (wanted_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) {
78277809 result.id = ConstCastResultIdFnCC;
78287810 return result;
78297811 }
7830 if (expected_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {
7812 if (wanted_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {
78317813 result.id = ConstCastResultIdFnVarArgs;
78327814 return result;
78337815 }
7834 if (expected_type->data.fn.is_generic != actual_type->data.fn.is_generic) {
7816 if (wanted_type->data.fn.is_generic != actual_type->data.fn.is_generic) {
78357817 result.id = ConstCastResultIdFnIsGeneric;
78367818 return result;
78377819 }
7838 if (!expected_type->data.fn.is_generic &&
7820 if (!wanted_type->data.fn.is_generic &&
78397821 actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable)
78407822 {
7841 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);
7823 ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.fn.fn_type_id.return_type,
7824 actual_type->data.fn.fn_type_id.return_type, source_node, false);
78427825 if (child.id != ConstCastResultIdOk) {
78437826 result.id = ConstCastResultIdFnReturnType;
78447827 result.data.return_type = allocate_nonzero<ConstCastOnly>(1);
......@@ -7846,9 +7829,11 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
78467829 return result;
78477830 }
78487831 }
7849 if (!expected_type->data.fn.is_generic && expected_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
7850 ConstCastOnly child = types_match_const_cast_only(ira, actual_type->data.fn.fn_type_id.async_allocator_type,
7851 expected_type->data.fn.fn_type_id.async_allocator_type, source_node);
7832 if (!wanted_type->data.fn.is_generic && wanted_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
7833 ConstCastOnly child = types_match_const_cast_only(ira,
7834 actual_type->data.fn.fn_type_id.async_allocator_type,
7835 wanted_type->data.fn.fn_type_id.async_allocator_type,
7836 source_node, false);
78527837 if (child.id != ConstCastResultIdOk) {
78537838 result.id = ConstCastResultIdAsyncAllocatorType;
78547839 result.data.async_allocator_type = allocate_nonzero<ConstCastOnly>(1);
......@@ -7856,22 +7841,23 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
78567841 return result;
78577842 }
78587843 }
7859 if (expected_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {
7844 if (wanted_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {
78607845 result.id = ConstCastResultIdFnArgCount;
78617846 return result;
78627847 }
7863 if (expected_type->data.fn.fn_type_id.next_param_index != actual_type->data.fn.fn_type_id.next_param_index) {
7848 if (wanted_type->data.fn.fn_type_id.next_param_index != actual_type->data.fn.fn_type_id.next_param_index) {
78647849 result.id = ConstCastResultIdFnGenericArgCount;
78657850 return result;
78667851 }
7867 assert(expected_type->data.fn.is_generic ||
7868 expected_type->data.fn.fn_type_id.next_param_index == expected_type->data.fn.fn_type_id.param_count);
7869 for (size_t i = 0; i < expected_type->data.fn.fn_type_id.next_param_index; i += 1) {
7852 assert(wanted_type->data.fn.is_generic ||
7853 wanted_type->data.fn.fn_type_id.next_param_index == wanted_type->data.fn.fn_type_id.param_count);
7854 for (size_t i = 0; i < wanted_type->data.fn.fn_type_id.next_param_index; i += 1) {
78707855 // note it's reversed for parameters
78717856 FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i];
7872 FnTypeParamInfo *expected_param_info = &expected_type->data.fn.fn_type_id.param_info[i];
7857 FnTypeParamInfo *expected_param_info = &wanted_type->data.fn.fn_type_id.param_info[i];
78737858
7874 ConstCastOnly arg_child = types_match_const_cast_only(ira, actual_param_info->type, expected_param_info->type, source_node);
7859 ConstCastOnly arg_child = types_match_const_cast_only(ira, actual_param_info->type,
7860 expected_param_info->type, source_node, false);
78757861 if (arg_child.id != ConstCastResultIdOk) {
78767862 result.id = ConstCastResultIdFnArg;
78777863 result.data.fn_arg.arg_index = i;
......@@ -7899,11 +7885,12 @@ enum ImplicitCastMatchResult {
78997885 ImplicitCastMatchResultReportedError,
79007886};
79017887
7902static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, TypeTableEntry *expected_type,
7888static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, TypeTableEntry *wanted_type,
79037889 TypeTableEntry *actual_type, IrInstruction *value)
79047890{
79057891 AstNode *source_node = value->source_node;
7906 ConstCastOnly const_cast_result = types_match_const_cast_only(ira, expected_type, actual_type, source_node);
7892 ConstCastOnly const_cast_result = types_match_const_cast_only(ira, wanted_type, actual_type,
7893 source_node, false);
79077894 if (const_cast_result.id == ConstCastResultIdOk) {
79087895 return ImplicitCastMatchResultYes;
79097896 }
......@@ -7918,21 +7905,21 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
79187905 missing_errors = &const_cast_result.data.error_union_error_set->data.error_set.missing_errors;
79197906 } else if (const_cast_result.data.error_union_error_set->id == ConstCastResultIdErrSetGlobal) {
79207907 ErrorMsg *msg = ir_add_error(ira, value,
7921 buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));
7908 buf_sprintf("expected '%s', found '%s'", buf_ptr(&wanted_type->name), buf_ptr(&actual_type->name)));
79227909 add_error_note(ira->codegen, msg, value->source_node,
79237910 buf_sprintf("unable to cast global error set into smaller set"));
79247911 return ImplicitCastMatchResultReportedError;
79257912 }
79267913 } else if (const_cast_result.id == ConstCastResultIdErrSetGlobal) {
79277914 ErrorMsg *msg = ir_add_error(ira, value,
7928 buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));
7915 buf_sprintf("expected '%s', found '%s'", buf_ptr(&wanted_type->name), buf_ptr(&actual_type->name)));
79297916 add_error_note(ira->codegen, msg, value->source_node,
79307917 buf_sprintf("unable to cast global error set into smaller set"));
79317918 return ImplicitCastMatchResultReportedError;
79327919 }
79337920 if (missing_errors != nullptr) {
79347921 ErrorMsg *msg = ir_add_error(ira, value,
7935 buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));
7922 buf_sprintf("expected '%s', found '%s'", buf_ptr(&wanted_type->name), buf_ptr(&actual_type->name)));
79367923 for (size_t i = 0; i < missing_errors->length; i += 1) {
79377924 ErrorTableEntry *error_entry = missing_errors->at(i);
79387925 add_error_note(ira->codegen, msg, error_entry->decl_node,
......@@ -7943,133 +7930,168 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
79437930 }
79447931
79457932 // implicit conversion from ?T to ?U
7946 if (expected_type->id == TypeTableEntryIdMaybe && actual_type->id == TypeTableEntryIdMaybe) {
7947 ImplicitCastMatchResult res = ir_types_match_with_implicit_cast(ira, expected_type->data.maybe.child_type,
7933 if (wanted_type->id == TypeTableEntryIdOptional && actual_type->id == TypeTableEntryIdOptional) {
7934 ImplicitCastMatchResult res = ir_types_match_with_implicit_cast(ira, wanted_type->data.maybe.child_type,
79487935 actual_type->data.maybe.child_type, value);
79497936 if (res != ImplicitCastMatchResultNo)
79507937 return res;
79517938 }
79527939
79537940 // implicit conversion from non maybe type to maybe type
7954 if (expected_type->id == TypeTableEntryIdMaybe) {
7955 ImplicitCastMatchResult res = ir_types_match_with_implicit_cast(ira, expected_type->data.maybe.child_type,
7941 if (wanted_type->id == TypeTableEntryIdOptional) {
7942 ImplicitCastMatchResult res = ir_types_match_with_implicit_cast(ira, wanted_type->data.maybe.child_type,
79567943 actual_type, value);
79577944 if (res != ImplicitCastMatchResultNo)
79587945 return res;
79597946 }
79607947
79617948 // implicit conversion from null literal to maybe type
7962 if (expected_type->id == TypeTableEntryIdMaybe &&
7949 if (wanted_type->id == TypeTableEntryIdOptional &&
79637950 actual_type->id == TypeTableEntryIdNull)
79647951 {
79657952 return ImplicitCastMatchResultYes;
79667953 }
79677954
79687955 // implicit T to U!T
7969 if (expected_type->id == TypeTableEntryIdErrorUnion &&
7970 ir_types_match_with_implicit_cast(ira, expected_type->data.error_union.payload_type, actual_type, value))
7956 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
7957 ir_types_match_with_implicit_cast(ira, wanted_type->data.error_union.payload_type, actual_type, value))
79717958 {
79727959 return ImplicitCastMatchResultYes;
79737960 }
79747961
79757962 // implicit conversion from error set to error union type
7976 if (expected_type->id == TypeTableEntryIdErrorUnion &&
7963 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
79777964 actual_type->id == TypeTableEntryIdErrorSet)
79787965 {
79797966 return ImplicitCastMatchResultYes;
79807967 }
79817968
79827969 // implicit conversion from T to U!?T
7983 if (expected_type->id == TypeTableEntryIdErrorUnion &&
7984 expected_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe &&
7970 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
7971 wanted_type->data.error_union.payload_type->id == TypeTableEntryIdOptional &&
79857972 ir_types_match_with_implicit_cast(ira,
7986 expected_type->data.error_union.payload_type->data.maybe.child_type,
7973 wanted_type->data.error_union.payload_type->data.maybe.child_type,
79877974 actual_type, value))
79887975 {
79897976 return ImplicitCastMatchResultYes;
79907977 }
79917978
79927979 // implicit widening conversion
7993 if (expected_type->id == TypeTableEntryIdInt &&
7980 if (wanted_type->id == TypeTableEntryIdInt &&
79947981 actual_type->id == TypeTableEntryIdInt &&
7995 expected_type->data.integral.is_signed == actual_type->data.integral.is_signed &&
7996 expected_type->data.integral.bit_count >= actual_type->data.integral.bit_count)
7982 wanted_type->data.integral.is_signed == actual_type->data.integral.is_signed &&
7983 wanted_type->data.integral.bit_count >= actual_type->data.integral.bit_count)
79977984 {
79987985 return ImplicitCastMatchResultYes;
79997986 }
80007987
80017988 // small enough unsigned ints can get casted to large enough signed ints
8002 if (expected_type->id == TypeTableEntryIdInt && expected_type->data.integral.is_signed &&
7989 if (wanted_type->id == TypeTableEntryIdInt && wanted_type->data.integral.is_signed &&
80037990 actual_type->id == TypeTableEntryIdInt && !actual_type->data.integral.is_signed &&
8004 expected_type->data.integral.bit_count > actual_type->data.integral.bit_count)
7991 wanted_type->data.integral.bit_count > actual_type->data.integral.bit_count)
80057992 {
80067993 return ImplicitCastMatchResultYes;
80077994 }
80087995
80097996 // implicit float widening conversion
8010 if (expected_type->id == TypeTableEntryIdFloat &&
7997 if (wanted_type->id == TypeTableEntryIdFloat &&
80117998 actual_type->id == TypeTableEntryIdFloat &&
8012 expected_type->data.floating.bit_count >= actual_type->data.floating.bit_count)
7999 wanted_type->data.floating.bit_count >= actual_type->data.floating.bit_count)
80138000 {
80148001 return ImplicitCastMatchResultYes;
80158002 }
80168003
80178004 // implicit [N]T to []const T
8018 if (is_slice(expected_type) && actual_type->id == TypeTableEntryIdArray) {
8019 TypeTableEntry *ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry;
8005 if (is_slice(wanted_type) && actual_type->id == TypeTableEntryIdArray) {
8006 TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
80208007 assert(ptr_type->id == TypeTableEntryIdPointer);
80218008
80228009 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
8023 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
8010 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
8011 source_node, false).id == ConstCastResultIdOk)
80248012 {
80258013 return ImplicitCastMatchResultYes;
80268014 }
80278015 }
80288016
80298017 // implicit &const [N]T to []const T
8030 if (is_slice(expected_type) &&
8018 if (is_slice(wanted_type) &&
80318019 actual_type->id == TypeTableEntryIdPointer &&
8020 actual_type->data.pointer.ptr_len == PtrLenSingle &&
80328021 actual_type->data.pointer.is_const &&
80338022 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
80348023 {
8035 TypeTableEntry *ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry;
8024 TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
80368025 assert(ptr_type->id == TypeTableEntryIdPointer);
80378026
80388027 TypeTableEntry *array_type = actual_type->data.pointer.child_type;
80398028
80408029 if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
8041 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
8030 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type,
8031 source_node, false).id == ConstCastResultIdOk)
80428032 {
80438033 return ImplicitCastMatchResultYes;
80448034 }
80458035 }
80468036
80478037 // implicit [N]T to &const []const T
8048 if (expected_type->id == TypeTableEntryIdPointer &&
8049 expected_type->data.pointer.is_const &&
8050 is_slice(expected_type->data.pointer.child_type) &&
8038 if (wanted_type->id == TypeTableEntryIdPointer &&
8039 wanted_type->data.pointer.is_const &&
8040 wanted_type->data.pointer.ptr_len == PtrLenSingle &&
8041 is_slice(wanted_type->data.pointer.child_type) &&
80518042 actual_type->id == TypeTableEntryIdArray)
80528043 {
80538044 TypeTableEntry *ptr_type =
8054 expected_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;
8045 wanted_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;
80558046 assert(ptr_type->id == TypeTableEntryIdPointer);
80568047 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
8057 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
8048 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type,
8049 actual_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
8050 {
8051 return ImplicitCastMatchResultYes;
8052 }
8053 }
8054
8055 // implicit *[N]T to [*]T
8056 if (wanted_type->id == TypeTableEntryIdPointer &&
8057 wanted_type->data.pointer.ptr_len == PtrLenUnknown &&
8058 actual_type->id == TypeTableEntryIdPointer &&
8059 actual_type->data.pointer.ptr_len == PtrLenSingle &&
8060 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray &&
8061 types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
8062 actual_type->data.pointer.child_type->data.array.child_type, source_node,
8063 !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
8064 {
8065 return ImplicitCastMatchResultYes;
8066 }
8067
8068 // implicit *[N]T to []T
8069 if (is_slice(wanted_type) &&
8070 actual_type->id == TypeTableEntryIdPointer &&
8071 actual_type->data.pointer.ptr_len == PtrLenSingle &&
8072 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
8073 {
8074 TypeTableEntry *slice_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
8075 assert(slice_ptr_type->id == TypeTableEntryIdPointer);
8076 if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
8077 actual_type->data.pointer.child_type->data.array.child_type, source_node,
8078 !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk)
80588079 {
80598080 return ImplicitCastMatchResultYes;
80608081 }
80618082 }
80628083
80638084 // implicit [N]T to ?[]const T
8064 if (expected_type->id == TypeTableEntryIdMaybe &&
8065 is_slice(expected_type->data.maybe.child_type) &&
8085 if (wanted_type->id == TypeTableEntryIdOptional &&
8086 is_slice(wanted_type->data.maybe.child_type) &&
80668087 actual_type->id == TypeTableEntryIdArray)
80678088 {
80688089 TypeTableEntry *ptr_type =
8069 expected_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;
8090 wanted_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;
80708091 assert(ptr_type->id == TypeTableEntryIdPointer);
80718092 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
8072 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
8093 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type,
8094 actual_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
80738095 {
80748096 return ImplicitCastMatchResultYes;
80758097 }
......@@ -8081,15 +8103,16 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
80818103 if (actual_type->id == TypeTableEntryIdComptimeFloat ||
80828104 actual_type->id == TypeTableEntryIdComptimeInt)
80838105 {
8084 if (expected_type->id == TypeTableEntryIdPointer &&
8085 expected_type->data.pointer.is_const)
8106 if (wanted_type->id == TypeTableEntryIdPointer &&
8107 wanted_type->data.pointer.ptr_len == PtrLenSingle &&
8108 wanted_type->data.pointer.is_const)
80868109 {
8087 if (ir_num_lit_fits_in_other_type(ira, value, expected_type->data.pointer.child_type, false)) {
8110 if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.pointer.child_type, false)) {
80888111 return ImplicitCastMatchResultYes;
80898112 } else {
80908113 return ImplicitCastMatchResultReportedError;
80918114 }
8092 } else if (ir_num_lit_fits_in_other_type(ira, value, expected_type, false)) {
8115 } else if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, false)) {
80938116 return ImplicitCastMatchResultYes;
80948117 } else {
80958118 return ImplicitCastMatchResultReportedError;
......@@ -8099,38 +8122,41 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
80998122 // implicit typed number to integer or float literal.
81008123 // works when the number is known
81018124 if (value->value.special == ConstValSpecialStatic) {
8102 if (actual_type->id == TypeTableEntryIdInt && expected_type->id == TypeTableEntryIdComptimeInt) {
8125 if (actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdComptimeInt) {
81038126 return ImplicitCastMatchResultYes;
8104 } else if (actual_type->id == TypeTableEntryIdFloat && expected_type->id == TypeTableEntryIdComptimeFloat) {
8127 } else if (actual_type->id == TypeTableEntryIdFloat && wanted_type->id == TypeTableEntryIdComptimeFloat) {
81058128 return ImplicitCastMatchResultYes;
81068129 }
81078130 }
81088131
81098132 // implicit union to its enum tag type
8110 if (expected_type->id == TypeTableEntryIdEnum && actual_type->id == TypeTableEntryIdUnion &&
8133 if (wanted_type->id == TypeTableEntryIdEnum && actual_type->id == TypeTableEntryIdUnion &&
81118134 (actual_type->data.unionation.decl_node->data.container_decl.auto_enum ||
81128135 actual_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
81138136 {
81148137 type_ensure_zero_bits_known(ira->codegen, actual_type);
8115 if (actual_type->data.unionation.tag_type == expected_type) {
8138 if (actual_type->data.unionation.tag_type == wanted_type) {
81168139 return ImplicitCastMatchResultYes;
81178140 }
81188141 }
81198142
81208143 // implicit enum to union which has the enum as the tag type
8121 if (expected_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum &&
8122 (expected_type->data.unionation.decl_node->data.container_decl.auto_enum ||
8123 expected_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
8144 if (wanted_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum &&
8145 (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum ||
8146 wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
81248147 {
8125 type_ensure_zero_bits_known(ira->codegen, expected_type);
8126 if (expected_type->data.unionation.tag_type == actual_type) {
8148 type_ensure_zero_bits_known(ira->codegen, wanted_type);
8149 if (wanted_type->data.unionation.tag_type == actual_type) {
81278150 return ImplicitCastMatchResultYes;
81288151 }
81298152 }
81308153
81318154 // implicit enum to &const union which has the enum as the tag type
8132 if (actual_type->id == TypeTableEntryIdEnum && expected_type->id == TypeTableEntryIdPointer) {
8133 TypeTableEntry *union_type = expected_type->data.pointer.child_type;
8155 if (actual_type->id == TypeTableEntryIdEnum &&
8156 wanted_type->id == TypeTableEntryIdPointer &&
8157 wanted_type->data.pointer.ptr_len == PtrLenSingle)
8158 {
8159 TypeTableEntry *union_type = wanted_type->data.pointer.child_type;
81348160 if (union_type->data.unionation.decl_node->data.container_decl.auto_enum ||
81358161 union_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)
81368162 {
......@@ -8141,6 +8167,17 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
81418167 }
81428168 }
81438169
8170 // implicit T to *T where T is zero bits
8171 if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
8172 types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
8173 actual_type, source_node, false).id == ConstCastResultIdOk)
8174 {
8175 type_ensure_zero_bits_known(ira->codegen, actual_type);
8176 if (!type_has_bits(actual_type)) {
8177 return ImplicitCastMatchResultYes;
8178 }
8179 }
8180
81448181 // implicit undefined literal to anything
81458182 if (actual_type->id == TypeTableEntryIdUndefined) {
81468183 return ImplicitCastMatchResultYes;
......@@ -8149,7 +8186,11 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
81498186 // implicitly take a const pointer to something
81508187 if (!type_requires_comptime(actual_type)) {
81518188 TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);
8152 if (types_match_const_cast_only(ira, expected_type, const_ptr_actual, source_node).id == ConstCastResultIdOk) {
8189 if (wanted_type->id == TypeTableEntryIdPointer &&
8190 wanted_type->data.pointer.ptr_len == PtrLenSingle &&
8191 types_match_const_cast_only(ira, wanted_type, const_ptr_actual,
8192 source_node, false).id == ConstCastResultIdOk)
8193 {
81538194 return ImplicitCastMatchResultYes;
81548195 }
81558196 }
......@@ -8390,9 +8431,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
83908431 TypeTableEntry *cur_payload_type = cur_type->data.error_union.payload_type;
83918432
83928433 bool const_cast_prev = types_match_const_cast_only(ira, prev_payload_type, cur_payload_type,
8393 source_node).id == ConstCastResultIdOk;
8434 source_node, false).id == ConstCastResultIdOk;
83948435 bool const_cast_cur = types_match_const_cast_only(ira, cur_payload_type, prev_payload_type,
8395 source_node).id == ConstCastResultIdOk;
8436 source_node, false).id == ConstCastResultIdOk;
83968437
83978438 if (const_cast_prev || const_cast_cur) {
83988439 if (const_cast_cur) {
......@@ -8479,11 +8520,11 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
84798520 continue;
84808521 }
84818522
8482 if (types_match_const_cast_only(ira, prev_type, cur_type, source_node).id == ConstCastResultIdOk) {
8523 if (types_match_const_cast_only(ira, prev_type, cur_type, source_node, false).id == ConstCastResultIdOk) {
84838524 continue;
84848525 }
84858526
8486 if (types_match_const_cast_only(ira, cur_type, prev_type, source_node).id == ConstCastResultIdOk) {
8527 if (types_match_const_cast_only(ira, cur_type, prev_type, source_node, false).id == ConstCastResultIdOk) {
84878528 prev_inst = cur_inst;
84888529 continue;
84898530 }
......@@ -8506,13 +8547,15 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
85068547 }
85078548
85088549 if (prev_type->id == TypeTableEntryIdErrorUnion &&
8509 types_match_const_cast_only(ira, prev_type->data.error_union.payload_type, cur_type, source_node).id == ConstCastResultIdOk)
8550 types_match_const_cast_only(ira, prev_type->data.error_union.payload_type, cur_type,
8551 source_node, false).id == ConstCastResultIdOk)
85108552 {
85118553 continue;
85128554 }
85138555
85148556 if (cur_type->id == TypeTableEntryIdErrorUnion &&
8515 types_match_const_cast_only(ira, cur_type->data.error_union.payload_type, prev_type, source_node).id == ConstCastResultIdOk)
8557 types_match_const_cast_only(ira, cur_type->data.error_union.payload_type, prev_type,
8558 source_node, false).id == ConstCastResultIdOk)
85168559 {
85178560 if (err_set_type != nullptr) {
85188561 TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
......@@ -8533,14 +8576,16 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
85338576 continue;
85348577 }
85358578
8536 if (prev_type->id == TypeTableEntryIdMaybe &&
8537 types_match_const_cast_only(ira, prev_type->data.maybe.child_type, cur_type, source_node).id == ConstCastResultIdOk)
8579 if (prev_type->id == TypeTableEntryIdOptional &&
8580 types_match_const_cast_only(ira, prev_type->data.maybe.child_type, cur_type,
8581 source_node, false).id == ConstCastResultIdOk)
85388582 {
85398583 continue;
85408584 }
85418585
8542 if (cur_type->id == TypeTableEntryIdMaybe &&
8543 types_match_const_cast_only(ira, cur_type->data.maybe.child_type, prev_type, source_node).id == ConstCastResultIdOk)
8586 if (cur_type->id == TypeTableEntryIdOptional &&
8587 types_match_const_cast_only(ira, cur_type->data.maybe.child_type, prev_type,
8588 source_node, false).id == ConstCastResultIdOk)
85448589 {
85458590 prev_inst = cur_inst;
85468591 continue;
......@@ -8577,8 +8622,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
85778622 }
85788623
85798624 if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray &&
8580 cur_type->data.array.len != prev_type->data.array.len &&
8581 types_match_const_cast_only(ira, cur_type->data.array.child_type, prev_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
8625 cur_type->data.array.len != prev_type->data.array.len &&
8626 types_match_const_cast_only(ira, cur_type->data.array.child_type, prev_type->data.array.child_type,
8627 source_node, false).id == ConstCastResultIdOk)
85828628 {
85838629 convert_to_const_slice = true;
85848630 prev_inst = cur_inst;
......@@ -8586,8 +8632,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
85868632 }
85878633
85888634 if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray &&
8589 cur_type->data.array.len != prev_type->data.array.len &&
8590 types_match_const_cast_only(ira, prev_type->data.array.child_type, cur_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
8635 cur_type->data.array.len != prev_type->data.array.len &&
8636 types_match_const_cast_only(ira, prev_type->data.array.child_type, cur_type->data.array.child_type,
8637 source_node, false).id == ConstCastResultIdOk)
85918638 {
85928639 convert_to_const_slice = true;
85938640 continue;
......@@ -8596,8 +8643,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
85968643 if (cur_type->id == TypeTableEntryIdArray && is_slice(prev_type) &&
85978644 (prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const ||
85988645 cur_type->data.array.len == 0) &&
8599 types_match_const_cast_only(ira, prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
8600 cur_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
8646 types_match_const_cast_only(ira,
8647 prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
8648 cur_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
86018649 {
86028650 convert_to_const_slice = false;
86038651 continue;
......@@ -8606,8 +8654,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
86068654 if (prev_type->id == TypeTableEntryIdArray && is_slice(cur_type) &&
86078655 (cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const ||
86088656 prev_type->data.array.len == 0) &&
8609 types_match_const_cast_only(ira, cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
8610 prev_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
8657 types_match_const_cast_only(ira,
8658 cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
8659 prev_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
86118660 {
86128661 prev_inst = cur_inst;
86138662 convert_to_const_slice = false;
......@@ -8692,7 +8741,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
86928741 ir_add_error_node(ira, source_node,
86938742 buf_sprintf("unable to make maybe out of number literal"));
86948743 return ira->codegen->builtin_types.entry_invalid;
8695 } else if (prev_inst->value.type->id == TypeTableEntryIdMaybe) {
8744 } else if (prev_inst->value.type->id == TypeTableEntryIdOptional) {
86968745 return prev_inst->value.type;
86978746 } else {
86988747 return get_maybe_type(ira->codegen, prev_inst->value.type);
......@@ -8735,10 +8784,12 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
87358784 zig_unreachable();
87368785 case CastOpErrSet:
87378786 case CastOpBitCast:
8787 case CastOpPtrOfArrayToSlice:
87388788 zig_panic("TODO");
87398789 case CastOpNoop:
87408790 {
8741 copy_const_val(const_val, other_val, other_val->special == ConstValSpecialStatic);
8791 bool same_global_refs = other_val->special == ConstValSpecialStatic;
8792 copy_const_val(const_val, other_val, same_global_refs);
87428793 const_val->type = new_type;
87438794 break;
87448795 }
......@@ -8804,7 +8855,7 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
88048855static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
88058856 TypeTableEntry *wanted_type, CastOp cast_op, bool need_alloca)
88068857{
8807 if (value->value.special != ConstValSpecialRuntime &&
8858 if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) &&
88088859 cast_op != CastOpResizeSlice && cast_op != CastOpBytesToSlice)
88098860 {
88108861 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
......@@ -8822,6 +8873,63 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst
88228873 }
88238874}
88248875
8876static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, IrInstruction *source_instr,
8877 IrInstruction *value, TypeTableEntry *wanted_type)
8878{
8879 assert(value->value.type->id == TypeTableEntryIdPointer);
8880 wanted_type = adjust_ptr_align(ira->codegen, wanted_type, value->value.type->data.pointer.alignment);
8881
8882 if (instr_is_comptime(value)) {
8883 ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value);
8884 if (pointee->special != ConstValSpecialRuntime) {
8885 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
8886 source_instr->source_node, wanted_type);
8887 result->value.type = wanted_type;
8888 result->value.data.x_ptr.special = ConstPtrSpecialBaseArray;
8889 result->value.data.x_ptr.mut = value->value.data.x_ptr.mut;
8890 result->value.data.x_ptr.data.base_array.array_val = pointee;
8891 result->value.data.x_ptr.data.base_array.elem_index = 0;
8892 result->value.data.x_ptr.data.base_array.is_cstr = false;
8893 return result;
8894 }
8895 }
8896
8897 IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node,
8898 wanted_type, value, CastOpBitCast);
8899 result->value.type = wanted_type;
8900 return result;
8901}
8902
8903static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr,
8904 IrInstruction *value, TypeTableEntry *wanted_type)
8905{
8906 wanted_type = adjust_slice_align(ira->codegen, wanted_type, value->value.type->data.pointer.alignment);
8907
8908 if (instr_is_comptime(value)) {
8909 ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value);
8910 if (pointee->special != ConstValSpecialRuntime) {
8911 assert(value->value.type->id == TypeTableEntryIdPointer);
8912 TypeTableEntry *array_type = value->value.type->data.pointer.child_type;
8913 assert(is_slice(wanted_type));
8914 bool is_const = wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
8915
8916 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
8917 source_instr->source_node, wanted_type);
8918 init_const_slice(ira->codegen, &result->value, pointee, 0, array_type->data.array.len, is_const);
8919 result->value.data.x_struct.fields[slice_ptr_index].data.x_ptr.mut =
8920 value->value.data.x_ptr.mut;
8921 result->value.type = wanted_type;
8922 return result;
8923 }
8924 }
8925
8926 IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node,
8927 wanted_type, value, CastOpPtrOfArrayToSlice);
8928 result->value.type = wanted_type;
8929 ir_add_alloca(ira, result, wanted_type);
8930 return result;
8931}
8932
88258933static bool is_container(TypeTableEntry *type) {
88268934 return type->id == TypeTableEntryIdStruct ||
88278935 type->id == TypeTableEntryIdEnum ||
......@@ -9115,7 +9223,7 @@ static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
91159223}
91169224
91179225static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {
9118 assert(wanted_type->id == TypeTableEntryIdMaybe);
9226 assert(wanted_type->id == TypeTableEntryIdOptional);
91199227
91209228 if (instr_is_comptime(value)) {
91219229 TypeTableEntry *payload_type = wanted_type->data.maybe.child_type;
......@@ -9129,15 +9237,19 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc
91299237
91309238 IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
91319239 source_instr->scope, source_instr->source_node);
9132 const_instruction->base.value.type = wanted_type;
91339240 const_instruction->base.value.special = ConstValSpecialStatic;
9134 const_instruction->base.value.data.x_maybe = val;
9241 if (get_codegen_ptr_type(wanted_type) != nullptr) {
9242 copy_const_val(&const_instruction->base.value, val, val->data.x_ptr.mut == ConstPtrMutComptimeConst);
9243 } else {
9244 const_instruction->base.value.data.x_optional = val;
9245 }
9246 const_instruction->base.value.type = wanted_type;
91359247 return &const_instruction->base;
91369248 }
91379249
91389250 IrInstruction *result = ir_build_maybe_wrap(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
91399251 result->value.type = wanted_type;
9140 result->value.data.rh_maybe = RuntimeHintMaybeNonNull;
9252 result->value.data.rh_maybe = RuntimeHintOptionalNonNull;
91419253 ir_add_alloca(ira, result, wanted_type);
91429254 return result;
91439255}
......@@ -9279,16 +9391,21 @@ static IrInstruction *ir_analyze_cast_ref(IrAnalyze *ira, IrInstruction *source_
92799391}
92809392
92819393static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {
9282 assert(wanted_type->id == TypeTableEntryIdMaybe);
9394 assert(wanted_type->id == TypeTableEntryIdOptional);
92839395 assert(instr_is_comptime(value));
92849396
92859397 ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
92869398 assert(val);
92879399
92889400 IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, source_instr->scope, source_instr->source_node);
9289 const_instruction->base.value.type = wanted_type;
92909401 const_instruction->base.value.special = ConstValSpecialStatic;
9291 const_instruction->base.value.data.x_maybe = nullptr;
9402 if (get_codegen_ptr_type(wanted_type) != nullptr) {
9403 const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
9404 const_instruction->base.value.data.x_ptr.data.hard_coded_addr.addr = 0;
9405 } else {
9406 const_instruction->base.value.data.x_optional = nullptr;
9407 }
9408 const_instruction->base.value.type = wanted_type;
92929409 return &const_instruction->base;
92939410}
92949411
......@@ -9300,9 +9417,19 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
93009417
93019418 if (value->id == IrInstructionIdLoadPtr) {
93029419 IrInstructionLoadPtr *load_ptr_inst = (IrInstructionLoadPtr *) value;
9420
93039421 if (load_ptr_inst->ptr->value.type->data.pointer.is_const) {
93049422 return load_ptr_inst->ptr;
93059423 }
9424
9425 type_ensure_zero_bits_known(ira->codegen, value->value.type);
9426 if (type_is_invalid(value->value.type)) {
9427 return ira->codegen->invalid_instruction;
9428 }
9429
9430 if (!type_has_bits(value->value.type)) {
9431 return load_ptr_inst->ptr;
9432 }
93069433 }
93079434
93089435 if (instr_is_comptime(value)) {
......@@ -9810,7 +9937,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
98109937 }
98119938
98129939 // explicit match or non-const to const
9813 if (types_match_const_cast_only(ira, wanted_type, actual_type, source_node).id == ConstCastResultIdOk) {
9940 if (types_match_const_cast_only(ira, wanted_type, actual_type, source_node, false).id == ConstCastResultIdOk) {
98149941 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
98159942 }
98169943
......@@ -9856,7 +9983,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
98569983 TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
98579984 assert(ptr_type->id == TypeTableEntryIdPointer);
98589985 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
9859 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
9986 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
9987 source_node, false).id == ConstCastResultIdOk)
98609988 {
98619989 return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
98629990 }
......@@ -9874,7 +10002,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
987410002 TypeTableEntry *array_type = actual_type->data.pointer.child_type;
987510003
987610004 if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
9877 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
10005 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type,
10006 source_node, false).id == ConstCastResultIdOk)
987810007 {
987910008 return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
988010009 }
......@@ -9890,7 +10019,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
989010019 wanted_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;
989110020 assert(ptr_type->id == TypeTableEntryIdPointer);
989210021 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
9893 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
10022 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
10023 source_node, false).id == ConstCastResultIdOk)
989410024 {
989510025 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);
989610026 if (type_is_invalid(cast1->value.type))
......@@ -9905,7 +10035,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
990510035 }
990610036
990710037 // explicit cast from [N]T to ?[]const N
9908 if (wanted_type->id == TypeTableEntryIdMaybe &&
10038 if (wanted_type->id == TypeTableEntryIdOptional &&
990910039 is_slice(wanted_type->data.maybe.child_type) &&
991010040 actual_type->id == TypeTableEntryIdArray)
991110041 {
......@@ -9913,7 +10043,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
991310043 wanted_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;
991410044 assert(ptr_type->id == TypeTableEntryIdPointer);
991510045 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
9916 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
10046 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
10047 source_node, false).id == ConstCastResultIdOk)
991710048 {
991810049 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value);
991910050 if (type_is_invalid(cast1->value.type))
......@@ -9973,10 +10104,44 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
997310104 }
997410105 }
997510106
9976 // explicit cast from child type of maybe type to maybe type
9977 if (wanted_type->id == TypeTableEntryIdMaybe) {
10107 // explicit *[N]T to [*]T
10108 if (wanted_type->id == TypeTableEntryIdPointer &&
10109 wanted_type->data.pointer.ptr_len == PtrLenUnknown &&
10110 actual_type->id == TypeTableEntryIdPointer &&
10111 actual_type->data.pointer.ptr_len == PtrLenSingle &&
10112 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray &&
10113 actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment &&
10114 types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
10115 actual_type->data.pointer.child_type->data.array.child_type, source_node,
10116 !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
10117 {
10118 return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type);
10119 }
10120
10121 // explicit *[N]T to []T
10122 if (is_slice(wanted_type) &&
10123 actual_type->id == TypeTableEntryIdPointer &&
10124 actual_type->data.pointer.ptr_len == PtrLenSingle &&
10125 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
10126 {
10127 TypeTableEntry *slice_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
10128 assert(slice_ptr_type->id == TypeTableEntryIdPointer);
10129 if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
10130 actual_type->data.pointer.child_type->data.array.child_type, source_node,
10131 !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk)
10132 {
10133 return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type);
10134 }
10135 }
10136
10137
10138 // explicit cast from T to ?T
10139 // note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism
10140 if (wanted_type->id == TypeTableEntryIdOptional) {
997810141 TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type;
9979 if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node).id == ConstCastResultIdOk) {
10142 if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node,
10143 false).id == ConstCastResultIdOk)
10144 {
998010145 return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
998110146 } else if (actual_type->id == TypeTableEntryIdComptimeInt ||
998210147 actual_type->id == TypeTableEntryIdComptimeFloat)
......@@ -10003,7 +10168,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1000310168 }
1000410169
1000510170 // explicit cast from null literal to maybe type
10006 if (wanted_type->id == TypeTableEntryIdMaybe &&
10171 if (wanted_type->id == TypeTableEntryIdOptional &&
1000710172 actual_type->id == TypeTableEntryIdNull)
1000810173 {
1000910174 return ir_analyze_null_to_maybe(ira, source_instr, value, wanted_type);
......@@ -10011,7 +10176,9 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1001110176
1001210177 // explicit cast from child type of error type to error type
1001310178 if (wanted_type->id == TypeTableEntryIdErrorUnion) {
10014 if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type, source_node).id == ConstCastResultIdOk) {
10179 if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type,
10180 source_node, false).id == ConstCastResultIdOk)
10181 {
1001510182 return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
1001610183 } else if (actual_type->id == TypeTableEntryIdComptimeInt ||
1001710184 actual_type->id == TypeTableEntryIdComptimeFloat)
......@@ -10024,7 +10191,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1002410191 }
1002510192 }
1002610193
10027 // explicit cast from [N]T to %[]const T
10194 // explicit cast from [N]T to E![]const T
1002810195 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
1002910196 is_slice(wanted_type->data.error_union.payload_type) &&
1003010197 actual_type->id == TypeTableEntryIdArray)
......@@ -10033,7 +10200,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1003310200 wanted_type->data.error_union.payload_type->data.structure.fields[slice_ptr_index].type_entry;
1003410201 assert(ptr_type->id == TypeTableEntryIdPointer);
1003510202 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
10036 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
10203 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
10204 source_node, false).id == ConstCastResultIdOk)
1003710205 {
1003810206 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value);
1003910207 if (type_is_invalid(cast1->value.type))
......@@ -10054,13 +10222,13 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1005410222 return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type);
1005510223 }
1005610224
10057 // explicit cast from T to %?T
10225 // explicit cast from T to E!?T
1005810226 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
10059 wanted_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe &&
10060 actual_type->id != TypeTableEntryIdMaybe)
10227 wanted_type->data.error_union.payload_type->id == TypeTableEntryIdOptional &&
10228 actual_type->id != TypeTableEntryIdOptional)
1006110229 {
1006210230 TypeTableEntry *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type;
10063 if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node).id == ConstCastResultIdOk ||
10231 if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk ||
1006410232 actual_type->id == TypeTableEntryIdNull ||
1006510233 actual_type->id == TypeTableEntryIdComptimeInt ||
1006610234 actual_type->id == TypeTableEntryIdComptimeFloat)
......@@ -10078,7 +10246,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1007810246 }
1007910247
1008010248 // explicit cast from number literal to another type
10081 // explicit cast from number literal to &const integer
10249 // explicit cast from number literal to *const integer
1008210250 if (actual_type->id == TypeTableEntryIdComptimeFloat ||
1008310251 actual_type->id == TypeTableEntryIdComptimeInt)
1008410252 {
......@@ -10212,7 +10380,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1021210380 TypeTableEntry *array_type = wanted_type->data.pointer.child_type;
1021310381 if (array_type->id == TypeTableEntryIdArray && array_type->data.array.len == 1 &&
1021410382 types_match_const_cast_only(ira, array_type->data.array.child_type,
10215 actual_type->data.pointer.child_type, source_node).id == ConstCastResultIdOk)
10383 actual_type->data.pointer.child_type, source_node,
10384 !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
1021610385 {
1021710386 if (wanted_type->data.pointer.alignment > actual_type->data.pointer.alignment) {
1021810387 ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment"));
......@@ -10228,6 +10397,20 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1022810397 }
1022910398 }
1023010399
10400 // explicit cast from T to *T where T is zero bits
10401 if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
10402 types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
10403 actual_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
10404 {
10405 type_ensure_zero_bits_known(ira->codegen, actual_type);
10406 if (type_is_invalid(actual_type)) {
10407 return ira->codegen->invalid_instruction;
10408 }
10409 if (!type_has_bits(actual_type)) {
10410 return ir_get_ref(ira, source_instr, value, false, false);
10411 }
10412 }
10413
1023110414
1023210415 // explicit cast from undefined to anything
1023310416 if (actual_type->id == TypeTableEntryIdUndefined) {
......@@ -10237,7 +10420,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1023710420 // explicit cast from something to const pointer of it
1023810421 if (!type_requires_comptime(actual_type)) {
1023910422 TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);
10240 if (types_match_const_cast_only(ira, wanted_type, const_ptr_actual, source_node).id == ConstCastResultIdOk) {
10423 if (types_match_const_cast_only(ira, wanted_type, const_ptr_actual, source_node, false).id == ConstCastResultIdOk) {
1024110424 return ir_analyze_cast_ref(ira, source_instr, value, wanted_type);
1024210425 }
1024310426 }
......@@ -10302,6 +10485,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
1030210485 IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
1030310486 source_instruction->source_node, child_type);
1030410487 copy_const_val(&result->value, pointee, ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst);
10488 result->value.type = child_type;
1030510489 return result;
1030610490 }
1030710491 }
......@@ -10619,6 +10803,16 @@ static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) {
1061910803 }
1062010804}
1062110805
10806static bool optional_value_is_null(ConstExprValue *val) {
10807 assert(val->special == ConstValSpecialStatic);
10808 if (get_codegen_ptr_type(val->type) != nullptr) {
10809 return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr &&
10810 val->data.x_ptr.data.hard_coded_addr.addr == 0;
10811 } else {
10812 return val->data.x_optional == nullptr;
10813 }
10814}
10815
1062210816static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
1062310817 IrInstruction *op1 = bin_op_instruction->op1->other;
1062410818 IrInstruction *op2 = bin_op_instruction->op2->other;
......@@ -10627,8 +10821,8 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
1062710821 IrBinOp op_id = bin_op_instruction->op_id;
1062810822 bool is_equality_cmp = (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq);
1062910823 if (is_equality_cmp &&
10630 ((op1->value.type->id == TypeTableEntryIdNull && op2->value.type->id == TypeTableEntryIdMaybe) ||
10631 (op2->value.type->id == TypeTableEntryIdNull && op1->value.type->id == TypeTableEntryIdMaybe) ||
10824 ((op1->value.type->id == TypeTableEntryIdNull && op2->value.type->id == TypeTableEntryIdOptional) ||
10825 (op2->value.type->id == TypeTableEntryIdNull && op1->value.type->id == TypeTableEntryIdOptional) ||
1063210826 (op1->value.type->id == TypeTableEntryIdNull && op2->value.type->id == TypeTableEntryIdNull)))
1063310827 {
1063410828 if (op1->value.type->id == TypeTableEntryIdNull && op2->value.type->id == TypeTableEntryIdNull) {
......@@ -10648,7 +10842,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
1064810842 ConstExprValue *maybe_val = ir_resolve_const(ira, maybe_op, UndefBad);
1064910843 if (!maybe_val)
1065010844 return ira->codegen->builtin_types.entry_invalid;
10651 bool is_null = (maybe_val->data.x_maybe == nullptr);
10845 bool is_null = optional_value_is_null(maybe_val);
1065210846 ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base);
1065310847 out_val->data.x_bool = (op_id == IrBinOpCmpEq) ? is_null : !is_null;
1065410848 return ira->codegen->builtin_types.entry_bool;
......@@ -10797,7 +10991,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
1079710991 case TypeTableEntryIdStruct:
1079810992 case TypeTableEntryIdUndefined:
1079910993 case TypeTableEntryIdNull:
10800 case TypeTableEntryIdMaybe:
10994 case TypeTableEntryIdOptional:
1080110995 case TypeTableEntryIdErrorUnion:
1080210996 case TypeTableEntryIdUnion:
1080310997 ir_add_error_node(ira, source_node,
......@@ -11135,7 +11329,13 @@ static TypeTableEntry *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *
1113511329
1113611330static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
1113711331 IrInstruction *op1 = bin_op_instruction->op1->other;
11332 if (type_is_invalid(op1->value.type))
11333 return ira->codegen->builtin_types.entry_invalid;
11334
1113811335 IrInstruction *op2 = bin_op_instruction->op2->other;
11336 if (type_is_invalid(op2->value.type))
11337 return ira->codegen->builtin_types.entry_invalid;
11338
1113911339 IrBinOp op_id = bin_op_instruction->op_id;
1114011340
1114111341 // look for pointer math
......@@ -11621,61 +11821,6 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi
1162111821 zig_unreachable();
1162211822}
1162311823
11624enum VarClassRequired {
11625 VarClassRequiredAny,
11626 VarClassRequiredConst,
11627 VarClassRequiredIllegal,
11628};
11629
11630static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) {
11631 switch (type_entry->id) {
11632 case TypeTableEntryIdInvalid:
11633 zig_unreachable();
11634 case TypeTableEntryIdUnreachable:
11635 return VarClassRequiredIllegal;
11636 case TypeTableEntryIdBool:
11637 case TypeTableEntryIdInt:
11638 case TypeTableEntryIdFloat:
11639 case TypeTableEntryIdVoid:
11640 case TypeTableEntryIdErrorSet:
11641 case TypeTableEntryIdFn:
11642 case TypeTableEntryIdPromise:
11643 return VarClassRequiredAny;
11644 case TypeTableEntryIdComptimeFloat:
11645 case TypeTableEntryIdComptimeInt:
11646 case TypeTableEntryIdUndefined:
11647 case TypeTableEntryIdBlock:
11648 case TypeTableEntryIdNull:
11649 case TypeTableEntryIdOpaque:
11650 case TypeTableEntryIdMetaType:
11651 case TypeTableEntryIdNamespace:
11652 case TypeTableEntryIdBoundFn:
11653 case TypeTableEntryIdArgTuple:
11654 return VarClassRequiredConst;
11655
11656 case TypeTableEntryIdPointer:
11657 if (type_entry->data.pointer.child_type->id == TypeTableEntryIdOpaque) {
11658 return VarClassRequiredAny;
11659 } else {
11660 return get_var_class_required(type_entry->data.pointer.child_type);
11661 }
11662 case TypeTableEntryIdArray:
11663 return get_var_class_required(type_entry->data.array.child_type);
11664 case TypeTableEntryIdMaybe:
11665 return get_var_class_required(type_entry->data.maybe.child_type);
11666 case TypeTableEntryIdErrorUnion:
11667 return get_var_class_required(type_entry->data.error_union.payload_type);
11668
11669 case TypeTableEntryIdStruct:
11670 case TypeTableEntryIdEnum:
11671 case TypeTableEntryIdUnion:
11672 // TODO check the fields of these things and make sure that they don't recursively
11673 // contain any of the other variable classes
11674 return VarClassRequiredAny;
11675 }
11676 zig_unreachable();
11677}
11678
1167911824static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) {
1168011825 VariableTableEntry *var = decl_var_instruction->var;
1168111826
......@@ -11710,36 +11855,41 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
1171011855 if (type_is_invalid(result_type)) {
1171111856 result_type = ira->codegen->builtin_types.entry_invalid;
1171211857 } else {
11713 switch (get_var_class_required(result_type)) {
11714 case VarClassRequiredIllegal:
11858 type_ensure_zero_bits_known(ira->codegen, result_type);
11859 if (type_is_invalid(result_type)) {
11860 result_type = ira->codegen->builtin_types.entry_invalid;
11861 }
11862 }
11863
11864 if (!type_is_invalid(result_type)) {
11865 if (result_type->id == TypeTableEntryIdUnreachable ||
11866 result_type->id == TypeTableEntryIdOpaque)
11867 {
11868 ir_add_error_node(ira, source_node,
11869 buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name)));
11870 result_type = ira->codegen->builtin_types.entry_invalid;
11871 } else if (type_requires_comptime(result_type)) {
11872 var_class_requires_const = true;
11873 if (!var->src_is_const && !is_comptime_var) {
1171511874 ir_add_error_node(ira, source_node,
11716 buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name)));
11875 buf_sprintf("variable of type '%s' must be const or comptime",
11876 buf_ptr(&result_type->name)));
1171711877 result_type = ira->codegen->builtin_types.entry_invalid;
11718 break;
11719 case VarClassRequiredConst:
11878 }
11879 } else {
11880 if (casted_init_value->value.special == ConstValSpecialStatic &&
11881 casted_init_value->value.type->id == TypeTableEntryIdFn &&
11882 casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways)
11883 {
1172011884 var_class_requires_const = true;
1172111885 if (!var->src_is_const && !is_comptime_var) {
11722 ir_add_error_node(ira, source_node,
11723 buf_sprintf("variable of type '%s' must be const or comptime",
11724 buf_ptr(&result_type->name)));
11886 ErrorMsg *msg = ir_add_error_node(ira, source_node,
11887 buf_sprintf("functions marked inline must be stored in const or comptime var"));
11888 AstNode *proto_node = casted_init_value->value.data.x_ptr.data.fn.fn_entry->proto_node;
11889 add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here"));
1172511890 result_type = ira->codegen->builtin_types.entry_invalid;
1172611891 }
11727 break;
11728 case VarClassRequiredAny:
11729 if (casted_init_value->value.special == ConstValSpecialStatic &&
11730 casted_init_value->value.type->id == TypeTableEntryIdFn &&
11731 casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways)
11732 {
11733 var_class_requires_const = true;
11734 if (!var->src_is_const && !is_comptime_var) {
11735 ErrorMsg *msg = ir_add_error_node(ira, source_node,
11736 buf_sprintf("functions marked inline must be stored in const or comptime var"));
11737 AstNode *proto_node = casted_init_value->value.data.x_ptr.data.fn.fn_entry->proto_node;
11738 add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here"));
11739 result_type = ira->codegen->builtin_types.entry_invalid;
11740 }
11741 }
11742 break;
11892 }
1174311893 }
1174411894 }
1174511895
......@@ -11914,7 +12064,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
1191412064 case TypeTableEntryIdComptimeInt:
1191512065 case TypeTableEntryIdUndefined:
1191612066 case TypeTableEntryIdNull:
11917 case TypeTableEntryIdMaybe:
12067 case TypeTableEntryIdOptional:
1191812068 case TypeTableEntryIdErrorUnion:
1191912069 case TypeTableEntryIdErrorSet:
1192012070 case TypeTableEntryIdNamespace:
......@@ -11938,7 +12088,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
1193812088 case TypeTableEntryIdComptimeInt:
1193912089 case TypeTableEntryIdUndefined:
1194012090 case TypeTableEntryIdNull:
11941 case TypeTableEntryIdMaybe:
12091 case TypeTableEntryIdOptional:
1194212092 case TypeTableEntryIdErrorUnion:
1194312093 case TypeTableEntryIdErrorSet:
1194412094 zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name));
......@@ -11965,22 +12115,24 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {
1196512115static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
1196612116 IrInstructionErrorReturnTrace *instruction)
1196712117{
11968 if (instruction->nullable == IrInstructionErrorReturnTrace::Null) {
12118 if (instruction->optional == IrInstructionErrorReturnTrace::Null) {
1196912119 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
11970 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);
12120 TypeTableEntry *optional_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);
1197112121 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {
1197212122 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
11973 out_val->data.x_maybe = nullptr;
11974 return nullable_type;
12123 assert(get_codegen_ptr_type(optional_type) != nullptr);
12124 out_val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
12125 out_val->data.x_ptr.data.hard_coded_addr.addr = 0;
12126 return optional_type;
1197512127 }
1197612128 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11977 instruction->base.source_node, instruction->nullable);
12129 instruction->base.source_node, instruction->optional);
1197812130 ir_link_new_instruction(new_instruction, &instruction->base);
11979 return nullable_type;
12131 return optional_type;
1198012132 } else {
1198112133 assert(ira->codegen->have_err_ret_tracing);
1198212134 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11983 instruction->base.source_node, instruction->nullable);
12135 instruction->base.source_node, instruction->optional);
1198412136 ir_link_new_instruction(new_instruction, &instruction->base);
1198512137 return get_ptr_to_stack_trace_type(ira->codegen);
1198612138 }
......@@ -12620,6 +12772,10 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1262012772 inst_fn_type_id.return_type = specified_return_type;
1262112773 }
1262212774
12775 type_ensure_zero_bits_known(ira->codegen, specified_return_type);
12776 if (type_is_invalid(specified_return_type))
12777 return ira->codegen->builtin_types.entry_invalid;
12778
1262312779 if (type_requires_comptime(specified_return_type)) {
1262412780 // Throw out our work and call the function as if it were comptime.
1262512781 return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, FnInlineAuto);
......@@ -12854,6 +13010,12 @@ static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp
1285413010 if (type_is_invalid(ptr_type)) {
1285513011 return ira->codegen->builtin_types.entry_invalid;
1285613012 } else if (ptr_type->id == TypeTableEntryIdPointer) {
13013 if (ptr_type->data.pointer.ptr_len == PtrLenUnknown) {
13014 ir_add_error_node(ira, un_op_instruction->base.source_node,
13015 buf_sprintf("index syntax required for unknown-length pointer type '%s'",
13016 buf_ptr(&ptr_type->name)));
13017 return ira->codegen->builtin_types.entry_invalid;
13018 }
1285713019 child_type = ptr_type->data.pointer.child_type;
1285813020 } else {
1285913021 ir_add_error_node(ira, un_op_instruction->base.source_node,
......@@ -12902,7 +13064,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
1290213064 case TypeTableEntryIdComptimeInt:
1290313065 case TypeTableEntryIdUndefined:
1290413066 case TypeTableEntryIdNull:
12905 case TypeTableEntryIdMaybe:
13067 case TypeTableEntryIdOptional:
1290613068 case TypeTableEntryIdErrorUnion:
1290713069 case TypeTableEntryIdErrorSet:
1290813070 case TypeTableEntryIdEnum:
......@@ -12921,7 +13083,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
1292113083 case TypeTableEntryIdUnreachable:
1292213084 case TypeTableEntryIdOpaque:
1292313085 ir_add_error_node(ira, un_op_instruction->base.source_node,
12924 buf_sprintf("type '%s' not nullable", buf_ptr(&type_entry->name)));
13086 buf_sprintf("type '%s' not optional", buf_ptr(&type_entry->name)));
1292513087 return ira->codegen->builtin_types.entry_invalid;
1292613088 }
1292713089 zig_unreachable();
......@@ -13013,7 +13175,7 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio
1301313175 return ir_analyze_negation(ira, un_op_instruction);
1301413176 case IrUnOpDereference:
1301513177 return ir_analyze_dereference(ira, un_op_instruction);
13016 case IrUnOpMaybe:
13178 case IrUnOpOptional:
1301713179 return ir_analyze_maybe(ira, un_op_instruction);
1301813180 }
1301913181 zig_unreachable();
......@@ -13220,6 +13382,13 @@ static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, ui
1322013382 ptr_type->data.pointer.bit_offset, ptr_type->data.pointer.unaligned_bit_count);
1322113383}
1322213384
13385static TypeTableEntry *adjust_slice_align(CodeGen *g, TypeTableEntry *slice_type, uint32_t new_align) {
13386 assert(is_slice(slice_type));
13387 TypeTableEntry *ptr_type = adjust_ptr_align(g, slice_type->data.structure.fields[slice_ptr_index].type_entry,
13388 new_align);
13389 return get_slice_type(g, ptr_type);
13390}
13391
1322313392static TypeTableEntry *adjust_ptr_len(CodeGen *g, TypeTableEntry *ptr_type, PtrLen ptr_len) {
1322413393 assert(ptr_type->id == TypeTableEntryIdPointer);
1322513394 return get_pointer_to_type_extra(g,
......@@ -13794,10 +13963,14 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1379413963 ir_link_new_instruction(result, &field_ptr_instruction->base);
1379513964 return result->value.type;
1379613965 }
13797 } else if (container_type->id == TypeTableEntryIdArray) {
13966 } else if (is_array_ref(container_type)) {
1379813967 if (buf_eql_str(field_name, "len")) {
1379913968 ConstExprValue *len_val = create_const_vals(1);
13800 init_const_usize(ira->codegen, len_val, container_type->data.array.len);
13969 if (container_type->id == TypeTableEntryIdPointer) {
13970 init_const_usize(ira->codegen, len_val, container_type->data.pointer.child_type->data.array.len);
13971 } else {
13972 init_const_usize(ira->codegen, len_val, container_type->data.array.len);
13973 }
1380113974
1380213975 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
1380313976 bool ptr_is_const = true;
......@@ -14048,7 +14221,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1404814221 buf_ptr(&child_type->name), buf_ptr(field_name)));
1404914222 return ira->codegen->builtin_types.entry_invalid;
1405014223 }
14051 } else if (child_type->id == TypeTableEntryIdMaybe) {
14224 } else if (child_type->id == TypeTableEntryIdOptional) {
1405214225 if (buf_eql_str(field_name, "Child")) {
1405314226 bool ptr_is_const = true;
1405414227 bool ptr_is_volatile = false;
......@@ -14141,6 +14314,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1414114314
1414214315static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) {
1414314316 IrInstruction *ptr = load_ptr_instruction->ptr->other;
14317 if (type_is_invalid(ptr->value.type))
14318 return ira->codegen->builtin_types.entry_invalid;
14319
1414414320 IrInstruction *result = ir_get_deref(ira, &load_ptr_instruction->base, ptr);
1414514321 ir_link_new_instruction(result, &load_ptr_instruction->base);
1414614322 assert(result->value.type);
......@@ -14229,7 +14405,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
1422914405 case TypeTableEntryIdPointer:
1423014406 case TypeTableEntryIdArray:
1423114407 case TypeTableEntryIdStruct:
14232 case TypeTableEntryIdMaybe:
14408 case TypeTableEntryIdOptional:
1423314409 case TypeTableEntryIdErrorUnion:
1423414410 case TypeTableEntryIdErrorSet:
1423514411 case TypeTableEntryIdEnum:
......@@ -14497,7 +14673,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
1449714673 case TypeTableEntryIdStruct:
1449814674 case TypeTableEntryIdComptimeFloat:
1449914675 case TypeTableEntryIdComptimeInt:
14500 case TypeTableEntryIdMaybe:
14676 case TypeTableEntryIdOptional:
1450114677 case TypeTableEntryIdErrorUnion:
1450214678 case TypeTableEntryIdErrorSet:
1450314679 case TypeTableEntryIdEnum:
......@@ -14605,7 +14781,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
1460514781 case TypeTableEntryIdStruct:
1460614782 case TypeTableEntryIdComptimeFloat:
1460714783 case TypeTableEntryIdComptimeInt:
14608 case TypeTableEntryIdMaybe:
14784 case TypeTableEntryIdOptional:
1460914785 case TypeTableEntryIdErrorUnion:
1461014786 case TypeTableEntryIdErrorSet:
1461114787 case TypeTableEntryIdEnum:
......@@ -14676,7 +14852,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
1467614852 case TypeTableEntryIdPointer:
1467714853 case TypeTableEntryIdArray:
1467814854 case TypeTableEntryIdStruct:
14679 case TypeTableEntryIdMaybe:
14855 case TypeTableEntryIdOptional:
1468014856 case TypeTableEntryIdErrorUnion:
1468114857 case TypeTableEntryIdErrorSet:
1468214858 case TypeTableEntryIdEnum:
......@@ -14700,14 +14876,14 @@ static TypeTableEntry *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIn
1470014876
1470114877 TypeTableEntry *type_entry = value->value.type;
1470214878
14703 if (type_entry->id == TypeTableEntryIdMaybe) {
14879 if (type_entry->id == TypeTableEntryIdOptional) {
1470414880 if (instr_is_comptime(value)) {
1470514881 ConstExprValue *maybe_val = ir_resolve_const(ira, value, UndefBad);
1470614882 if (!maybe_val)
1470714883 return ira->codegen->builtin_types.entry_invalid;
1470814884
1470914885 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
14710 out_val->data.x_bool = (maybe_val->data.x_maybe != nullptr);
14886 out_val->data.x_bool = !optional_value_is_null(maybe_val);
1471114887 return ira->codegen->builtin_types.entry_bool;
1471214888 }
1471314889
......@@ -14725,7 +14901,7 @@ static TypeTableEntry *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIn
1472514901}
1472614902
1472714903static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
14728 IrInstructionUnwrapMaybe *unwrap_maybe_instruction)
14904 IrInstructionUnwrapOptional *unwrap_maybe_instruction)
1472914905{
1473014906 IrInstruction *value = unwrap_maybe_instruction->value->other;
1473114907 if (type_is_invalid(value->value.type))
......@@ -14737,25 +14913,9 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
1473714913 TypeTableEntry *type_entry = ptr_type->data.pointer.child_type;
1473814914 if (type_is_invalid(type_entry)) {
1473914915 return ira->codegen->builtin_types.entry_invalid;
14740 } else if (type_entry->id == TypeTableEntryIdMetaType) {
14741 // surprise! actually this is just ??T not an unwrap maybe instruction
14742 ConstExprValue *ptr_val = const_ptr_pointee(ira->codegen, &value->value);
14743 assert(ptr_val->type->id == TypeTableEntryIdMetaType);
14744 TypeTableEntry *child_type = ptr_val->data.x_type;
14745
14746 type_ensure_zero_bits_known(ira->codegen, child_type);
14747 TypeTableEntry *layer1 = get_maybe_type(ira->codegen, child_type);
14748 TypeTableEntry *layer2 = get_maybe_type(ira->codegen, layer1);
14749
14750 IrInstruction *const_instr = ir_build_const_type(&ira->new_irb, unwrap_maybe_instruction->base.scope,
14751 unwrap_maybe_instruction->base.source_node, layer2);
14752 IrInstruction *result_instr = ir_get_ref(ira, &unwrap_maybe_instruction->base, const_instr,
14753 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile);
14754 ir_link_new_instruction(result_instr, &unwrap_maybe_instruction->base);
14755 return result_instr->value.type;
14756 } else if (type_entry->id != TypeTableEntryIdMaybe) {
14916 } else if (type_entry->id != TypeTableEntryIdOptional) {
1475714917 ir_add_error_node(ira, unwrap_maybe_instruction->value->source_node,
14758 buf_sprintf("expected nullable type, found '%s'", buf_ptr(&type_entry->name)));
14918 buf_sprintf("expected optional type, found '%s'", buf_ptr(&type_entry->name)));
1475914919 return ira->codegen->builtin_types.entry_invalid;
1476014920 }
1476114921 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
......@@ -14771,13 +14931,18 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
1477114931 ConstExprValue *maybe_val = const_ptr_pointee(ira->codegen, val);
1477214932
1477314933 if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) {
14774 if (!maybe_val->data.x_maybe) {
14934 if (optional_value_is_null(maybe_val)) {
1477514935 ir_add_error(ira, &unwrap_maybe_instruction->base, buf_sprintf("unable to unwrap null"));
1477614936 return ira->codegen->builtin_types.entry_invalid;
1477714937 }
1477814938 ConstExprValue *out_val = ir_build_const_from(ira, &unwrap_maybe_instruction->base);
1477914939 out_val->data.x_ptr.special = ConstPtrSpecialRef;
14780 out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_maybe;
14940 out_val->data.x_ptr.mut = val->data.x_ptr.mut;
14941 if (type_is_codegen_pointer(child_type)) {
14942 out_val->data.x_ptr.data.ref.pointee = maybe_val;
14943 } else {
14944 out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_optional;
14945 }
1478114946 return result_type;
1478214947 }
1478314948 }
......@@ -15101,7 +15266,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
1510115266 case TypeTableEntryIdStruct:
1510215267 case TypeTableEntryIdUndefined:
1510315268 case TypeTableEntryIdNull:
15104 case TypeTableEntryIdMaybe:
15269 case TypeTableEntryIdOptional:
1510515270 case TypeTableEntryIdBlock:
1510615271 case TypeTableEntryIdBoundFn:
1510715272 case TypeTableEntryIdArgTuple:
......@@ -15622,7 +15787,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
1562215787 case TypeTableEntryIdComptimeInt:
1562315788 case TypeTableEntryIdUndefined:
1562415789 case TypeTableEntryIdNull:
15625 case TypeTableEntryIdMaybe:
15790 case TypeTableEntryIdOptional:
1562615791 case TypeTableEntryIdErrorUnion:
1562715792 case TypeTableEntryIdErrorSet:
1562815793 case TypeTableEntryIdUnion:
......@@ -15743,11 +15908,6 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn
1574315908 return out_val->type;
1574415909 }
1574515910
15746 if (!target->value.type->data.enumeration.generate_name_table) {
15747 target->value.type->data.enumeration.generate_name_table = true;
15748 ira->codegen->name_table_enums.append(target->value.type);
15749 }
15750
1575115911 IrInstruction *result = ir_build_tag_name(&ira->new_irb, instruction->base.scope,
1575215912 instruction->base.source_node, target);
1575315913 ir_link_new_instruction(result, &instruction->base);
......@@ -16140,12 +16300,12 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop
1614016300 0, 0);
1614116301 fn_def_fields[6].type = get_maybe_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr));
1614216302 if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0) {
16143 fn_def_fields[6].data.x_maybe = create_const_vals(1);
16303 fn_def_fields[6].data.x_optional = create_const_vals(1);
1614416304 ConstExprValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name);
16145 init_const_slice(ira->codegen, fn_def_fields[6].data.x_maybe, lib_name, 0, buf_len(fn_node->lib_name), true);
16305 init_const_slice(ira->codegen, fn_def_fields[6].data.x_optional, lib_name, 0, buf_len(fn_node->lib_name), true);
16306 } else {
16307 fn_def_fields[6].data.x_optional = nullptr;
1614616308 }
16147 else
16148 fn_def_fields[6].data.x_maybe = nullptr;
1614916309 // return_type: type
1615016310 ensure_field_index(fn_def_val->type, "return_type", 7);
1615116311 fn_def_fields[7].special = ConstValSpecialStatic;
......@@ -16213,8 +16373,7 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop
1621316373 return true;
1621416374}
1621516375
16216static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *type_entry)
16217{
16376static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *type_entry) {
1621816377 assert(type_entry != nullptr);
1621916378 assert(!type_is_invalid(type_entry));
1622016379
......@@ -16239,38 +16398,67 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1623916398 enum_field_val->data.x_struct.fields = inner_fields;
1624016399 };
1624116400
16242 const auto create_ptr_like_type_info = [ira](const char *name, TypeTableEntry *ptr_type_entry) {
16401 const auto create_ptr_like_type_info = [ira](TypeTableEntry *ptr_type_entry) {
16402 TypeTableEntry *attrs_type;
16403 uint32_t size_enum_index;
16404 if (is_slice(ptr_type_entry)) {
16405 attrs_type = ptr_type_entry->data.structure.fields[slice_ptr_index].type_entry;
16406 size_enum_index = 2;
16407 } else if (ptr_type_entry->id == TypeTableEntryIdPointer) {
16408 attrs_type = ptr_type_entry;
16409 size_enum_index = (ptr_type_entry->data.pointer.ptr_len == PtrLenSingle) ? 0 : 1;
16410 } else {
16411 zig_unreachable();
16412 }
16413
16414 TypeTableEntry *type_info_pointer_type = ir_type_info_get_type(ira, "Pointer");
16415 ensure_complete_type(ira->codegen, type_info_pointer_type);
16416 assert(!type_is_invalid(type_info_pointer_type));
16417
1624316418 ConstExprValue *result = create_const_vals(1);
1624416419 result->special = ConstValSpecialStatic;
16245 result->type = ir_type_info_get_type(ira, name);
16420 result->type = type_info_pointer_type;
1624616421
16247 ConstExprValue *fields = create_const_vals(4);
16422 ConstExprValue *fields = create_const_vals(5);
1624816423 result->data.x_struct.fields = fields;
1624916424
16250 // is_const: bool
16251 ensure_field_index(result->type, "is_const", 0);
16425 // size: Size
16426 ensure_field_index(result->type, "size", 0);
16427 TypeTableEntry *type_info_pointer_size_type = ir_type_info_get_type(ira, "Size", type_info_pointer_type);
16428 ensure_complete_type(ira->codegen, type_info_pointer_size_type);
16429 assert(!type_is_invalid(type_info_pointer_size_type));
1625216430 fields[0].special = ConstValSpecialStatic;
16253 fields[0].type = ira->codegen->builtin_types.entry_bool;
16254 fields[0].data.x_bool = ptr_type_entry->data.pointer.is_const;
16255 // is_volatile: bool
16256 ensure_field_index(result->type, "is_volatile", 1);
16431 fields[0].type = type_info_pointer_size_type;
16432 bigint_init_unsigned(&fields[0].data.x_enum_tag, size_enum_index);
16433
16434 // is_const: bool
16435 ensure_field_index(result->type, "is_const", 1);
1625716436 fields[1].special = ConstValSpecialStatic;
1625816437 fields[1].type = ira->codegen->builtin_types.entry_bool;
16259 fields[1].data.x_bool = ptr_type_entry->data.pointer.is_volatile;
16260 // alignment: u32
16261 ensure_field_index(result->type, "alignment", 2);
16438 fields[1].data.x_bool = attrs_type->data.pointer.is_const;
16439 // is_volatile: bool
16440 ensure_field_index(result->type, "is_volatile", 2);
1626216441 fields[2].special = ConstValSpecialStatic;
16263 fields[2].type = ira->codegen->builtin_types.entry_u32;
16264 bigint_init_unsigned(&fields[2].data.x_bigint, ptr_type_entry->data.pointer.alignment);
16265 // child: type
16266 ensure_field_index(result->type, "child", 3);
16442 fields[2].type = ira->codegen->builtin_types.entry_bool;
16443 fields[2].data.x_bool = attrs_type->data.pointer.is_volatile;
16444 // alignment: u32
16445 ensure_field_index(result->type, "alignment", 3);
1626716446 fields[3].special = ConstValSpecialStatic;
16268 fields[3].type = ira->codegen->builtin_types.entry_type;
16269 fields[3].data.x_type = ptr_type_entry->data.pointer.child_type;
16447 fields[3].type = ira->codegen->builtin_types.entry_u32;
16448 bigint_init_unsigned(&fields[3].data.x_bigint, attrs_type->data.pointer.alignment);
16449 // child: type
16450 ensure_field_index(result->type, "child", 4);
16451 fields[4].special = ConstValSpecialStatic;
16452 fields[4].type = ira->codegen->builtin_types.entry_type;
16453 fields[4].data.x_type = attrs_type->data.pointer.child_type;
1627016454
1627116455 return result;
1627216456 };
1627316457
16458 if (type_entry == ira->codegen->builtin_types.entry_global_error_set) {
16459 zig_panic("TODO implement @typeInfo for global error set");
16460 }
16461
1627416462 ConstExprValue *result = nullptr;
1627516463 switch (type_entry->id)
1627616464 {
......@@ -16339,7 +16527,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1633916527 }
1634016528 case TypeTableEntryIdPointer:
1634116529 {
16342 result = create_ptr_like_type_info("Pointer", type_entry);
16530 result = create_ptr_like_type_info(type_entry);
1634316531 break;
1634416532 }
1634516533 case TypeTableEntryIdArray:
......@@ -16364,11 +16552,11 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1636416552
1636516553 break;
1636616554 }
16367 case TypeTableEntryIdMaybe:
16555 case TypeTableEntryIdOptional:
1636816556 {
1636916557 result = create_const_vals(1);
1637016558 result->special = ConstValSpecialStatic;
16371 result->type = ir_type_info_get_type(ira, "Nullable");
16559 result->type = ir_type_info_get_type(ira, "Optional");
1637216560
1637316561 ConstExprValue *fields = create_const_vals(1);
1637416562 result->data.x_struct.fields = fields;
......@@ -16570,8 +16758,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1657016758
1657116759 TypeTableEntry *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField");
1657216760
16573 for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++)
16574 {
16761 for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) {
1657516762 TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index];
1657616763 ConstExprValue *union_field_val = &union_field_array->data.x_array.s_none.elements[union_field_index];
1657716764
......@@ -16582,12 +16769,11 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1658216769 inner_fields[1].special = ConstValSpecialStatic;
1658316770 inner_fields[1].type = get_maybe_type(ira->codegen, type_info_enum_field_type);
1658416771
16585 if (fields[1].data.x_type == ira->codegen->builtin_types.entry_undef)
16586 inner_fields[1].data.x_maybe = nullptr;
16587 else
16588 {
16589 inner_fields[1].data.x_maybe = create_const_vals(1);
16590 make_enum_field_val(inner_fields[1].data.x_maybe, union_field->enum_field, type_info_enum_field_type);
16772 if (fields[1].data.x_type == ira->codegen->builtin_types.entry_undef) {
16773 inner_fields[1].data.x_optional = nullptr;
16774 } else {
16775 inner_fields[1].data.x_optional = create_const_vals(1);
16776 make_enum_field_val(inner_fields[1].data.x_optional, union_field->enum_field, type_info_enum_field_type);
1659116777 }
1659216778
1659316779 inner_fields[2].special = ConstValSpecialStatic;
......@@ -16612,15 +16798,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1661216798 case TypeTableEntryIdStruct:
1661316799 {
1661416800 if (type_entry->data.structure.is_slice) {
16615 Buf ptr_field_name = BUF_INIT;
16616 buf_init_from_str(&ptr_field_name, "ptr");
16617 TypeTableEntry *ptr_type = type_entry->data.structure.fields_by_name.get(&ptr_field_name)->type_entry;
16618 ensure_complete_type(ira->codegen, ptr_type);
16619 if (type_is_invalid(ptr_type))
16620 return nullptr;
16621 buf_deinit(&ptr_field_name);
16622
16623 result = create_ptr_like_type_info("Slice", ptr_type);
16801 result = create_ptr_like_type_info(type_entry);
1662416802 break;
1662516803 }
1662616804
......@@ -16651,8 +16829,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1665116829
1665216830 init_const_slice(ira->codegen, &fields[1], struct_field_array, 0, struct_field_count, false);
1665316831
16654 for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++)
16655 {
16832 for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++) {
1665616833 TypeStructField *struct_field = &type_entry->data.structure.fields[struct_field_index];
1665716834 ConstExprValue *struct_field_val = &struct_field_array->data.x_array.s_none.elements[struct_field_index];
1665816835
......@@ -16663,15 +16840,14 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1666316840 inner_fields[1].special = ConstValSpecialStatic;
1666416841 inner_fields[1].type = get_maybe_type(ira->codegen, ira->codegen->builtin_types.entry_usize);
1666516842
16666 if (!type_has_bits(struct_field->type_entry))
16667 inner_fields[1].data.x_maybe = nullptr;
16668 else
16669 {
16843 if (!type_has_bits(struct_field->type_entry)) {
16844 inner_fields[1].data.x_optional = nullptr;
16845 } else {
1667016846 size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, type_entry->type_ref, struct_field->gen_index);
16671 inner_fields[1].data.x_maybe = create_const_vals(1);
16672 inner_fields[1].data.x_maybe->special = ConstValSpecialStatic;
16673 inner_fields[1].data.x_maybe->type = ira->codegen->builtin_types.entry_usize;
16674 bigint_init_unsigned(&inner_fields[1].data.x_maybe->data.x_bigint, byte_offset);
16847 inner_fields[1].data.x_optional = create_const_vals(1);
16848 inner_fields[1].data.x_optional->special = ConstValSpecialStatic;
16849 inner_fields[1].data.x_optional->type = ira->codegen->builtin_types.entry_usize;
16850 bigint_init_unsigned(&inner_fields[1].data.x_optional->data.x_bigint, byte_offset);
1667516851 }
1667616852
1667716853 inner_fields[2].special = ConstValSpecialStatic;
......@@ -17896,7 +18072,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc
1789618072 case TypeTableEntryIdPromise:
1789718073 case TypeTableEntryIdArray:
1789818074 case TypeTableEntryIdStruct:
17899 case TypeTableEntryIdMaybe:
18075 case TypeTableEntryIdOptional:
1790018076 case TypeTableEntryIdErrorUnion:
1790118077 case TypeTableEntryIdErrorSet:
1790218078 case TypeTableEntryIdEnum:
......@@ -18422,30 +18598,6 @@ static TypeTableEntry *ir_analyze_instruction_check_statement_is_void(IrAnalyze
1842218598 return ira->codegen->builtin_types.entry_void;
1842318599}
1842418600
18425static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira,
18426 IrInstructionCanImplicitCast *instruction)
18427{
18428 IrInstruction *type_value = instruction->type_value->other;
18429 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
18430 if (type_is_invalid(type_entry))
18431 return ira->codegen->builtin_types.entry_invalid;
18432
18433 IrInstruction *target_value = instruction->target_value->other;
18434 if (type_is_invalid(target_value->value.type))
18435 return ira->codegen->builtin_types.entry_invalid;
18436
18437 ImplicitCastMatchResult result = ir_types_match_with_implicit_cast(ira, type_entry, target_value->value.type,
18438 target_value);
18439
18440 if (result == ImplicitCastMatchResultReportedError) {
18441 zig_panic("TODO refactor implicit cast tester to return bool without reporting errors");
18442 }
18443
18444 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
18445 out_val->data.x_bool = (result == ImplicitCastMatchResultYes);
18446 return ira->codegen->builtin_types.entry_bool;
18447}
18448
1844918601static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructionPanic *instruction) {
1845018602 IrInstruction *msg = instruction->msg->other;
1845118603 if (type_is_invalid(msg->value.type))
......@@ -18484,7 +18636,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
1848418636 old_align_bytes = fn_type_id.alignment;
1848518637 fn_type_id.alignment = align_bytes;
1848618638 result_type = get_fn_type(ira->codegen, &fn_type_id);
18487 } else if (target_type->id == TypeTableEntryIdMaybe &&
18639 } else if (target_type->id == TypeTableEntryIdOptional &&
1848818640 target_type->data.maybe.child_type->id == TypeTableEntryIdPointer)
1848918641 {
1849018642 TypeTableEntry *ptr_type = target_type->data.maybe.child_type;
......@@ -18492,7 +18644,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
1849218644 TypeTableEntry *better_ptr_type = adjust_ptr_align(ira->codegen, ptr_type, align_bytes);
1849318645
1849418646 result_type = get_maybe_type(ira->codegen, better_ptr_type);
18495 } else if (target_type->id == TypeTableEntryIdMaybe &&
18647 } else if (target_type->id == TypeTableEntryIdOptional &&
1849618648 target_type->data.maybe.child_type->id == TypeTableEntryIdFn)
1849718649 {
1849818650 FnTypeId fn_type_id = target_type->data.maybe.child_type->data.fn.fn_type_id;
......@@ -18650,7 +18802,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
1865018802 return;
1865118803 case TypeTableEntryIdStruct:
1865218804 zig_panic("TODO buf_write_value_bytes struct type");
18653 case TypeTableEntryIdMaybe:
18805 case TypeTableEntryIdOptional:
1865418806 zig_panic("TODO buf_write_value_bytes maybe type");
1865518807 case TypeTableEntryIdErrorUnion:
1865618808 zig_panic("TODO buf_write_value_bytes error union");
......@@ -18708,7 +18860,7 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
1870818860 zig_panic("TODO buf_read_value_bytes array type");
1870918861 case TypeTableEntryIdStruct:
1871018862 zig_panic("TODO buf_read_value_bytes struct type");
18711 case TypeTableEntryIdMaybe:
18863 case TypeTableEntryIdOptional:
1871218864 zig_panic("TODO buf_read_value_bytes maybe type");
1871318865 case TypeTableEntryIdErrorUnion:
1871418866 zig_panic("TODO buf_read_value_bytes error union");
......@@ -18946,9 +19098,6 @@ static TypeTableEntry *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstr
1894619098 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
1894719099 if (!val)
1894819100 return ira->codegen->builtin_types.entry_invalid;
18949 if (target->value.type->id == TypeTableEntryIdMaybe) {
18950 val = val->data.x_maybe;
18951 }
1895219101 if (val->type->id == TypeTableEntryIdPointer && val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
1895319102 IrInstruction *result = ir_create_const(&ira->new_irb, instruction->base.scope,
1895419103 instruction->base.source_node, usize);
......@@ -18973,6 +19122,9 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruc
1897319122 if (child_type->id == TypeTableEntryIdUnreachable) {
1897419123 ir_add_error(ira, &instruction->base, buf_sprintf("pointer to noreturn not allowed"));
1897519124 return ira->codegen->builtin_types.entry_invalid;
19125 } else if (child_type->id == TypeTableEntryIdOpaque && instruction->ptr_len == PtrLenUnknown) {
19126 ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque"));
19127 return ira->codegen->builtin_types.entry_invalid;
1897619128 }
1897719129
1897819130 uint32_t align_bytes;
......@@ -19624,7 +19776,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1962419776 case IrInstructionIdUnionInit:
1962519777 case IrInstructionIdStructFieldPtr:
1962619778 case IrInstructionIdUnionFieldPtr:
19627 case IrInstructionIdMaybeWrap:
19779 case IrInstructionIdOptionalWrap:
1962819780 case IrInstructionIdErrWrapCode:
1962919781 case IrInstructionIdErrWrapPayload:
1963019782 case IrInstructionIdCast:
......@@ -19684,8 +19836,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1968419836 return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
1968519837 case IrInstructionIdTestNonNull:
1968619838 return ir_analyze_instruction_test_non_null(ira, (IrInstructionTestNonNull *)instruction);
19687 case IrInstructionIdUnwrapMaybe:
19688 return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapMaybe *)instruction);
19839 case IrInstructionIdUnwrapOptional:
19840 return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapOptional *)instruction);
1968919841 case IrInstructionIdClz:
1969019842 return ir_analyze_instruction_clz(ira, (IrInstructionClz *)instruction);
1969119843 case IrInstructionIdCtz:
......@@ -19776,8 +19928,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1977619928 return ir_analyze_instruction_check_switch_prongs(ira, (IrInstructionCheckSwitchProngs *)instruction);
1977719929 case IrInstructionIdCheckStatementIsVoid:
1977819930 return ir_analyze_instruction_check_statement_is_void(ira, (IrInstructionCheckStatementIsVoid *)instruction);
19779 case IrInstructionIdCanImplicitCast:
19780 return ir_analyze_instruction_can_implicit_cast(ira, (IrInstructionCanImplicitCast *)instruction);
1978119931 case IrInstructionIdDeclRef:
1978219932 return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction);
1978319933 case IrInstructionIdPanic:
......@@ -19873,6 +20023,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1987320023static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction) {
1987420024 TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(ira, instruction);
1987520025 instruction->value.type = instruction_type;
20026
1987620027 if (instruction->other) {
1987720028 instruction->other->value.type = instruction_type;
1987820029 } else {
......@@ -20022,7 +20173,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2002220173 case IrInstructionIdSliceType:
2002320174 case IrInstructionIdSizeOf:
2002420175 case IrInstructionIdTestNonNull:
20025 case IrInstructionIdUnwrapMaybe:
20176 case IrInstructionIdUnwrapOptional:
2002620177 case IrInstructionIdClz:
2002720178 case IrInstructionIdCtz:
2002820179 case IrInstructionIdSwitchVar:
......@@ -20044,7 +20195,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2004420195 case IrInstructionIdFrameAddress:
2004520196 case IrInstructionIdTestErr:
2004620197 case IrInstructionIdUnwrapErrCode:
20047 case IrInstructionIdMaybeWrap:
20198 case IrInstructionIdOptionalWrap:
2004820199 case IrInstructionIdErrWrapCode:
2004920200 case IrInstructionIdErrWrapPayload:
2005020201 case IrInstructionIdFnProto:
......@@ -20057,7 +20208,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2005720208 case IrInstructionIdIntToEnum:
2005820209 case IrInstructionIdIntToErr:
2005920210 case IrInstructionIdErrToInt:
20060 case IrInstructionIdCanImplicitCast:
2006120211 case IrInstructionIdDeclRef:
2006220212 case IrInstructionIdErrName:
2006320213 case IrInstructionIdTypeName:
src/ir_print.cpp+8-19
......@@ -148,7 +148,7 @@ static const char *ir_un_op_id_str(IrUnOp op_id) {
148148 return "-%";
149149 case IrUnOpDereference:
150150 return "*";
151 case IrUnOpMaybe:
151 case IrUnOpOptional:
152152 return "?";
153153 }
154154 zig_unreachable();
......@@ -481,7 +481,7 @@ static void ir_print_test_null(IrPrint *irp, IrInstructionTestNonNull *instructi
481481 fprintf(irp->f, " != null");
482482}
483483
484static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapMaybe *instruction) {
484static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapOptional *instruction) {
485485 fprintf(irp->f, "&??*");
486486 ir_print_other_instruction(irp, instruction->value);
487487 if (!instruction->safety_check_on) {
......@@ -777,7 +777,7 @@ static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayl
777777 }
778778}
779779
780static void ir_print_maybe_wrap(IrPrint *irp, IrInstructionMaybeWrap *instruction) {
780static void ir_print_maybe_wrap(IrPrint *irp, IrInstructionOptionalWrap *instruction) {
781781 fprintf(irp->f, "@maybeWrap(");
782782 ir_print_other_instruction(irp, instruction->value);
783783 fprintf(irp->f, ")");
......@@ -913,14 +913,6 @@ static void ir_print_tag_name(IrPrint *irp, IrInstructionTagName *instruction) {
913913 ir_print_other_instruction(irp, instruction->target);
914914}
915915
916static void ir_print_can_implicit_cast(IrPrint *irp, IrInstructionCanImplicitCast *instruction) {
917 fprintf(irp->f, "@canImplicitCast(");
918 ir_print_other_instruction(irp, instruction->type_value);
919 fprintf(irp->f, ",");
920 ir_print_other_instruction(irp, instruction->target_value);
921 fprintf(irp->f, ")");
922}
923
924916static void ir_print_ptr_type(IrPrint *irp, IrInstructionPtrType *instruction) {
925917 fprintf(irp->f, "&");
926918 if (instruction->align_value != nullptr) {
......@@ -1040,7 +1032,7 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {
10401032
10411033static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) {
10421034 fprintf(irp->f, "@errorReturnTrace(");
1043 switch (instruction->nullable) {
1035 switch (instruction->optional) {
10441036 case IrInstructionErrorReturnTrace::Null:
10451037 fprintf(irp->f, "Null");
10461038 break;
......@@ -1356,8 +1348,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
13561348 case IrInstructionIdTestNonNull:
13571349 ir_print_test_null(irp, (IrInstructionTestNonNull *)instruction);
13581350 break;
1359 case IrInstructionIdUnwrapMaybe:
1360 ir_print_unwrap_maybe(irp, (IrInstructionUnwrapMaybe *)instruction);
1351 case IrInstructionIdUnwrapOptional:
1352 ir_print_unwrap_maybe(irp, (IrInstructionUnwrapOptional *)instruction);
13611353 break;
13621354 case IrInstructionIdCtz:
13631355 ir_print_ctz(irp, (IrInstructionCtz *)instruction);
......@@ -1473,8 +1465,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
14731465 case IrInstructionIdUnwrapErrPayload:
14741466 ir_print_unwrap_err_payload(irp, (IrInstructionUnwrapErrPayload *)instruction);
14751467 break;
1476 case IrInstructionIdMaybeWrap:
1477 ir_print_maybe_wrap(irp, (IrInstructionMaybeWrap *)instruction);
1468 case IrInstructionIdOptionalWrap:
1469 ir_print_maybe_wrap(irp, (IrInstructionOptionalWrap *)instruction);
14781470 break;
14791471 case IrInstructionIdErrWrapCode:
14801472 ir_print_err_wrap_code(irp, (IrInstructionErrWrapCode *)instruction);
......@@ -1524,9 +1516,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
15241516 case IrInstructionIdTagName:
15251517 ir_print_tag_name(irp, (IrInstructionTagName *)instruction);
15261518 break;
1527 case IrInstructionIdCanImplicitCast:
1528 ir_print_can_implicit_cast(irp, (IrInstructionCanImplicitCast *)instruction);
1529 break;
15301519 case IrInstructionIdPtrType:
15311520 ir_print_ptr_type(irp, (IrInstructionPtrType *)instruction);
15321521 break;
src/link.cpp+14-1
......@@ -391,6 +391,19 @@ static void construct_linker_job_elf(LinkJob *lj) {
391391 }
392392}
393393
394static void construct_linker_job_wasm(LinkJob *lj) {
395 CodeGen *g = lj->codegen;
396
397 lj->args.append("--relocatable"); // So lld doesn't look for _start.
398 lj->args.append("-o");
399 lj->args.append(buf_ptr(&lj->out_file));
400
401 // .o files
402 for (size_t i = 0; i < g->link_objects.length; i += 1) {
403 lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
404 }
405}
406
394407//static bool is_target_cyg_mingw(const ZigTarget *target) {
395408// return (target->os == ZigLLVM_Win32 && target->env_type == ZigLLVM_Cygnus) ||
396409// (target->os == ZigLLVM_Win32 && target->env_type == ZigLLVM_GNU);
......@@ -924,7 +937,7 @@ static void construct_linker_job(LinkJob *lj) {
924937 case ZigLLVM_MachO:
925938 return construct_linker_job_macho(lj);
926939 case ZigLLVM_Wasm:
927 zig_panic("TODO link wasm");
940 return construct_linker_job_wasm(lj);
928941 }
929942}
930943
src/main.cpp+15
......@@ -23,6 +23,7 @@ static int usage(const char *arg0) {
2323 " build-exe [source] create executable from source or object files\n"
2424 " build-lib [source] create library from source or object files\n"
2525 " build-obj [source] create object from source or assembly\n"
26 " builtin show the source code of that @import(\"builtin\")\n"
2627 " run [source] create executable and run immediately\n"
2728 " translate-c [source] convert c code to zig code\n"
2829 " targets list available compilation targets\n"
......@@ -214,6 +215,7 @@ static Buf *resolve_zig_lib_dir(void) {
214215enum Cmd {
215216 CmdInvalid,
216217 CmdBuild,
218 CmdBuiltin,
217219 CmdRun,
218220 CmdTest,
219221 CmdVersion,
......@@ -664,6 +666,8 @@ int main(int argc, char **argv) {
664666 out_type = OutTypeExe;
665667 } else if (strcmp(arg, "targets") == 0) {
666668 cmd = CmdTargets;
669 } else if (strcmp(arg, "builtin") == 0) {
670 cmd = CmdBuiltin;
667671 } else {
668672 fprintf(stderr, "Unrecognized command: %s\n", arg);
669673 return usage(arg0);
......@@ -681,6 +685,7 @@ int main(int argc, char **argv) {
681685 return usage(arg0);
682686 }
683687 break;
688 case CmdBuiltin:
684689 case CmdVersion:
685690 case CmdZen:
686691 case CmdTargets:
......@@ -727,6 +732,16 @@ int main(int argc, char **argv) {
727732 }
728733
729734 switch (cmd) {
735 case CmdBuiltin: {
736 Buf *zig_lib_dir_buf = resolve_zig_lib_dir();
737 CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, zig_lib_dir_buf);
738 Buf *builtin_source = codegen_generate_builtin_source(g);
739 if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {
740 fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout)));
741 return EXIT_FAILURE;
742 }
743 return EXIT_SUCCESS;
744 }
730745 case CmdRun:
731746 case CmdBuild:
732747 case CmdTranslateC:
src/parser.cpp+16-8
......@@ -1046,12 +1046,11 @@ static AstNode *ast_parse_fn_proto_partial(ParseContext *pc, size_t *token_index
10461046}
10471047
10481048/*
1049SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | PtrDerefExpression | SliceExpression)
1049SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ".*" | ".?")
10501050FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
10511051ArrayAccessExpression : token(LBracket) Expression token(RBracket)
10521052SliceExpression = "[" Expression ".." option(Expression) "]"
10531053FieldAccessExpression : token(Dot) token(Symbol)
1054PtrDerefExpression = ".*"
10551054StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
10561055*/
10571056static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
......@@ -1148,6 +1147,13 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,
11481147 AstNode *node = ast_create_node(pc, NodeTypePtrDeref, first_token);
11491148 node->data.ptr_deref_expr.target = primary_expr;
11501149
1150 primary_expr = node;
1151 } else if (token->id == TokenIdQuestion) {
1152 *token_index += 1;
1153
1154 AstNode *node = ast_create_node(pc, NodeTypeUnwrapOptional, first_token);
1155 node->data.unwrap_optional.expr = primary_expr;
1156
11511157 primary_expr = node;
11521158 } else {
11531159 ast_invalid_token_error(pc, token);
......@@ -1165,8 +1171,7 @@ static PrefixOp tok_to_prefix_op(Token *token) {
11651171 case TokenIdDash: return PrefixOpNegation;
11661172 case TokenIdMinusPercent: return PrefixOpNegationWrap;
11671173 case TokenIdTilde: return PrefixOpBinNot;
1168 case TokenIdMaybe: return PrefixOpMaybe;
1169 case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe;
1174 case TokenIdQuestion: return PrefixOpOptional;
11701175 case TokenIdAmpersand: return PrefixOpAddrOf;
11711176 default: return PrefixOpInvalid;
11721177 }
......@@ -2304,8 +2309,8 @@ static BinOpType ast_parse_ass_op(ParseContext *pc, size_t *token_index, bool ma
23042309}
23052310
23062311/*
2307UnwrapExpression : BoolOrExpression (UnwrapMaybe | UnwrapError) | BoolOrExpression
2308UnwrapMaybe : "??" BoolOrExpression
2312UnwrapExpression : BoolOrExpression (UnwrapOptional | UnwrapError) | BoolOrExpression
2313UnwrapOptional = "orelse" Expression
23092314UnwrapError = "catch" option("|" Symbol "|") Expression
23102315*/
23112316static AstNode *ast_parse_unwrap_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
......@@ -2315,14 +2320,14 @@ static AstNode *ast_parse_unwrap_expr(ParseContext *pc, size_t *token_index, boo
23152320
23162321 Token *token = &pc->tokens->at(*token_index);
23172322
2318 if (token->id == TokenIdDoubleQuestion) {
2323 if (token->id == TokenIdKeywordOrElse) {
23192324 *token_index += 1;
23202325
23212326 AstNode *rhs = ast_parse_expression(pc, token_index, true);
23222327
23232328 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
23242329 node->data.bin_op_expr.op1 = lhs;
2325 node->data.bin_op_expr.bin_op = BinOpTypeUnwrapMaybe;
2330 node->data.bin_op_expr.bin_op = BinOpTypeUnwrapOptional;
23262331 node->data.bin_op_expr.op2 = rhs;
23272332
23282333 return node;
......@@ -3028,6 +3033,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
30283033 case NodeTypePtrDeref:
30293034 visit_field(&node->data.ptr_deref_expr.target, visit, context);
30303035 break;
3036 case NodeTypeUnwrapOptional:
3037 visit_field(&node->data.unwrap_optional.expr, visit, context);
3038 break;
30313039 case NodeTypeUse:
30323040 visit_field(&node->data.use.expr, visit, context);
30333041 break;
src/target.cpp+5-2
......@@ -596,12 +596,15 @@ void resolve_target_object_format(ZigTarget *target) {
596596 case ZigLLVM_tce:
597597 case ZigLLVM_tcele:
598598 case ZigLLVM_thumbeb:
599 case ZigLLVM_wasm32:
600 case ZigLLVM_wasm64:
601599 case ZigLLVM_xcore:
602600 target->oformat= ZigLLVM_ELF;
603601 return;
604602
603 case ZigLLVM_wasm32:
604 case ZigLLVM_wasm64:
605 target->oformat = ZigLLVM_Wasm;
606 return;
607
605608 case ZigLLVM_ppc:
606609 case ZigLLVM_ppc64:
607610 if (is_os_darwin(target)) {
src/tokenizer.cpp+7-28
......@@ -134,6 +134,7 @@ static const struct ZigKeyword zig_keywords[] = {
134134 {"noalias", TokenIdKeywordNoAlias},
135135 {"null", TokenIdKeywordNull},
136136 {"or", TokenIdKeywordOr},
137 {"orelse", TokenIdKeywordOrElse},
137138 {"packed", TokenIdKeywordPacked},
138139 {"promise", TokenIdKeywordPromise},
139140 {"pub", TokenIdKeywordPub},
......@@ -215,7 +216,6 @@ enum TokenizeState {
215216 TokenizeStateSawGreaterThanGreaterThan,
216217 TokenizeStateSawDot,
217218 TokenizeStateSawDotDot,
218 TokenizeStateSawQuestionMark,
219219 TokenizeStateSawAtSign,
220220 TokenizeStateCharCode,
221221 TokenizeStateError,
......@@ -532,6 +532,10 @@ void tokenize(Buf *buf, Tokenization *out) {
532532 begin_token(&t, TokenIdComma);
533533 end_token(&t);
534534 break;
535 case '?':
536 begin_token(&t, TokenIdQuestion);
537 end_token(&t);
538 break;
535539 case '{':
536540 begin_token(&t, TokenIdLBrace);
537541 end_token(&t);
......@@ -624,33 +628,10 @@ void tokenize(Buf *buf, Tokenization *out) {
624628 begin_token(&t, TokenIdDot);
625629 t.state = TokenizeStateSawDot;
626630 break;
627 case '?':
628 begin_token(&t, TokenIdMaybe);
629 t.state = TokenizeStateSawQuestionMark;
630 break;
631631 default:
632632 invalid_char_error(&t, c);
633633 }
634634 break;
635 case TokenizeStateSawQuestionMark:
636 switch (c) {
637 case '?':
638 set_token_id(&t, t.cur_tok, TokenIdDoubleQuestion);
639 end_token(&t);
640 t.state = TokenizeStateStart;
641 break;
642 case '=':
643 set_token_id(&t, t.cur_tok, TokenIdMaybeAssign);
644 end_token(&t);
645 t.state = TokenizeStateStart;
646 break;
647 default:
648 t.pos -= 1;
649 end_token(&t);
650 t.state = TokenizeStateStart;
651 continue;
652 }
653 break;
654635 case TokenizeStateSawDot:
655636 switch (c) {
656637 case '.':
......@@ -1485,7 +1466,6 @@ void tokenize(Buf *buf, Tokenization *out) {
14851466 case TokenizeStateSawGreaterThan:
14861467 case TokenizeStateSawGreaterThanGreaterThan:
14871468 case TokenizeStateSawDot:
1488 case TokenizeStateSawQuestionMark:
14891469 case TokenizeStateSawAtSign:
14901470 case TokenizeStateSawStarPercent:
14911471 case TokenizeStateSawPlusPercent:
......@@ -1550,7 +1530,6 @@ const char * token_name(TokenId id) {
15501530 case TokenIdDash: return "-";
15511531 case TokenIdDivEq: return "/=";
15521532 case TokenIdDot: return ".";
1553 case TokenIdDoubleQuestion: return "??";
15541533 case TokenIdEllipsis2: return "..";
15551534 case TokenIdEllipsis3: return "...";
15561535 case TokenIdEof: return "EOF";
......@@ -1587,6 +1566,7 @@ const char * token_name(TokenId id) {
15871566 case TokenIdKeywordNoAlias: return "noalias";
15881567 case TokenIdKeywordNull: return "null";
15891568 case TokenIdKeywordOr: return "or";
1569 case TokenIdKeywordOrElse: return "orelse";
15901570 case TokenIdKeywordPacked: return "packed";
15911571 case TokenIdKeywordPromise: return "promise";
15921572 case TokenIdKeywordPub: return "pub";
......@@ -1609,8 +1589,7 @@ const char * token_name(TokenId id) {
16091589 case TokenIdLBrace: return "{";
16101590 case TokenIdLBracket: return "[";
16111591 case TokenIdLParen: return "(";
1612 case TokenIdMaybe: return "?";
1613 case TokenIdMaybeAssign: return "?=";
1592 case TokenIdQuestion: return "?";
16141593 case TokenIdMinusEq: return "-=";
16151594 case TokenIdMinusPercent: return "-%";
16161595 case TokenIdMinusPercentEq: return "-%=";
src/tokenizer.hpp+4-3
......@@ -41,7 +41,6 @@ enum TokenId {
4141 TokenIdDash,
4242 TokenIdDivEq,
4343 TokenIdDot,
44 TokenIdDoubleQuestion,
4544 TokenIdEllipsis2,
4645 TokenIdEllipsis3,
4746 TokenIdEof,
......@@ -76,6 +75,7 @@ enum TokenId {
7675 TokenIdKeywordNoAlias,
7776 TokenIdKeywordNull,
7877 TokenIdKeywordOr,
78 TokenIdKeywordOrElse,
7979 TokenIdKeywordPacked,
8080 TokenIdKeywordPromise,
8181 TokenIdKeywordPub,
......@@ -100,8 +100,7 @@ enum TokenId {
100100 TokenIdLBrace,
101101 TokenIdLBracket,
102102 TokenIdLParen,
103 TokenIdMaybe,
104 TokenIdMaybeAssign,
103 TokenIdQuestion,
105104 TokenIdMinusEq,
106105 TokenIdMinusPercent,
107106 TokenIdMinusPercentEq,
......@@ -170,6 +169,8 @@ struct Token {
170169 TokenCharLit char_lit;
171170 } data;
172171};
172// work around conflicting name Token which is also found in libclang
173typedef Token ZigToken;
173174
174175struct Tokenization {
175176 ZigList<Token> *tokens;
src/translate_c.cpp+45-14
......@@ -260,6 +260,12 @@ static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *ch
260260 return node;
261261}
262262
263static AstNode *trans_create_node_unwrap_null(Context *c, AstNode *child_node) {
264 AstNode *node = trans_create_node(c, NodeTypeUnwrapOptional);
265 node->data.unwrap_optional.expr = child_node;
266 return node;
267}
268
263269static AstNode *trans_create_node_bin_op(Context *c, AstNode *lhs_node, BinOpType op, AstNode *rhs_node) {
264270 AstNode *node = trans_create_node(c, NodeTypeBinOpExpr);
265271 node->data.bin_op_expr.op1 = lhs_node;
......@@ -276,8 +282,11 @@ static AstNode *maybe_suppress_result(Context *c, ResultUsed result_used, AstNod
276282 node);
277283}
278284
279static AstNode *trans_create_node_ptr_type(Context *c, bool is_const, bool is_volatile, AstNode *child_node) {
285static AstNode *trans_create_node_ptr_type(Context *c, bool is_const, bool is_volatile, AstNode *child_node, PtrLen ptr_len) {
280286 AstNode *node = trans_create_node(c, NodeTypePointerType);
287 node->data.pointer_type.star_token = allocate<ZigToken>(1);
288 node->data.pointer_type.star_token->id = (ptr_len == PtrLenSingle) ? TokenIdStar: TokenIdBracketStarBracket;
289 node->data.pointer_type.is_const = is_const;
281290 node->data.pointer_type.is_const = is_const;
282291 node->data.pointer_type.is_volatile = is_volatile;
283292 node->data.pointer_type.op_expr = child_node;
......@@ -379,7 +388,7 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *r
379388 fn_def->data.fn_def.fn_proto = fn_proto;
380389 fn_proto->data.fn_proto.fn_def_node = fn_def;
381390
382 AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, ref_node);
391 AstNode *unwrap_node = trans_create_node_unwrap_null(c, ref_node);
383392 AstNode *fn_call_node = trans_create_node(c, NodeTypeFnCallExpr);
384393 fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node;
385394
......@@ -406,10 +415,6 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *r
406415 return fn_def;
407416}
408417
409static AstNode *trans_create_node_unwrap_null(Context *c, AstNode *child) {
410 return trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, child);
411}
412
413418static AstNode *get_global(Context *c, Buf *name) {
414419 {
415420 auto entry = c->global_table.maybe_get(name);
......@@ -731,6 +736,30 @@ static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) {
731736 }
732737}
733738
739static bool type_is_opaque(Context *c, const Type *ty, const SourceLocation &source_loc) {
740 switch (ty->getTypeClass()) {
741 case Type::Builtin: {
742 const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty);
743 return builtin_ty->getKind() == BuiltinType::Void;
744 }
745 case Type::Record: {
746 const RecordType *record_ty = static_cast<const RecordType*>(ty);
747 return record_ty->getDecl()->getDefinition() == nullptr;
748 }
749 case Type::Elaborated: {
750 const ElaboratedType *elaborated_ty = static_cast<const ElaboratedType*>(ty);
751 return type_is_opaque(c, elaborated_ty->getNamedType().getTypePtr(), source_loc);
752 }
753 case Type::Typedef: {
754 const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty);
755 const TypedefNameDecl *typedef_decl = typedef_ty->getDecl();
756 return type_is_opaque(c, typedef_decl->getUnderlyingType().getTypePtr(), source_loc);
757 }
758 default:
759 return false;
760 }
761}
762
734763static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) {
735764 switch (ty->getTypeClass()) {
736765 case Type::Builtin:
......@@ -859,12 +888,14 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
859888 }
860889
861890 if (qual_type_child_is_fn_proto(child_qt)) {
862 return trans_create_node_prefix_op(c, PrefixOpMaybe, child_node);
891 return trans_create_node_prefix_op(c, PrefixOpOptional, child_node);
863892 }
864893
894 PtrLen ptr_len = type_is_opaque(c, child_qt.getTypePtr(), source_loc) ? PtrLenSingle : PtrLenUnknown;
895
865896 AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(),
866 child_qt.isVolatileQualified(), child_node);
867 return trans_create_node_prefix_op(c, PrefixOpMaybe, pointer_node);
897 child_qt.isVolatileQualified(), child_node, ptr_len);
898 return trans_create_node_prefix_op(c, PrefixOpOptional, pointer_node);
868899 }
869900 case Type::Typedef:
870901 {
......@@ -1048,7 +1079,7 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
10481079 return nullptr;
10491080 }
10501081 AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(),
1051 child_qt.isVolatileQualified(), child_type_node);
1082 child_qt.isVolatileQualified(), child_type_node, PtrLenUnknown);
10521083 return pointer_node;
10531084 }
10541085 case Type::BlockPointer:
......@@ -1941,7 +1972,7 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc
19411972 bool is_fn_ptr = qual_type_is_fn_ptr(stmt->getSubExpr()->getType());
19421973 if (is_fn_ptr)
19431974 return value_node;
1944 AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node);
1975 AstNode *unwrapped = trans_create_node_unwrap_null(c, value_node);
19451976 return trans_create_node_ptr_deref(c, unwrapped);
19461977 }
19471978 case UO_Plus:
......@@ -2572,7 +2603,7 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *
25722603 }
25732604 }
25742605 if (callee_node == nullptr) {
2575 callee_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, callee_raw_node);
2606 callee_node = trans_create_node_unwrap_null(c, callee_raw_node);
25762607 }
25772608 } else {
25782609 callee_node = callee_raw_node;
......@@ -4286,7 +4317,7 @@ static AstNode *trans_lookup_ast_maybe_fn(Context *c, AstNode *ref_node) {
42864317 return nullptr;
42874318 if (prefix_node->type != NodeTypePrefixOpExpr)
42884319 return nullptr;
4289 if (prefix_node->data.prefix_op_expr.prefix_op != PrefixOpMaybe)
4320 if (prefix_node->data.prefix_op_expr.prefix_op != PrefixOpOptional)
42904321 return nullptr;
42914322
42924323 AstNode *fn_proto_node = prefix_node->data.prefix_op_expr.primary_expr;
......@@ -4462,7 +4493,7 @@ static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *t
44624493 } else if (first_tok->id == CTokIdAsterisk) {
44634494 *tok_i += 1;
44644495
4465 node = trans_create_node_ptr_type(c, false, false, node);
4496 node = trans_create_node_ptr_type(c, false, false, node, PtrLenUnknown);
44664497 } else {
44674498 return node;
44684499 }
src/zig_llvm.cpp+1-1
......@@ -853,7 +853,7 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_
853853 return lld::mach_o::link(array_ref_args, diag);
854854
855855 case ZigLLVM_Wasm:
856 assert(false); // TODO ZigLLDLink for Wasm
856 return lld::wasm::link(array_ref_args, false, diag);
857857 }
858858 assert(false); // unreachable
859859 abort();
std/array_list.zig+70-40
......@@ -1,6 +1,7 @@
11const std = @import("index.zig");
22const debug = std.debug;
33const assert = debug.assert;
4const assertError = debug.assertError;
45const mem = std.mem;
56const Allocator = mem.Allocator;
67
......@@ -28,20 +29,33 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
2829 };
2930 }
3031
31 pub fn deinit(l: *const Self) void {
32 l.allocator.free(l.items);
32 pub fn deinit(self: *const Self) void {
33 self.allocator.free(self.items);
3334 }
3435
35 pub fn toSlice(l: *const Self) []align(A) T {
36 return l.items[0..l.len];
36 pub fn toSlice(self: *const Self) []align(A) T {
37 return self.items[0..self.len];
3738 }
3839
39 pub fn toSliceConst(l: *const Self) []align(A) const T {
40 return l.items[0..l.len];
40 pub fn toSliceConst(self: *const Self) []align(A) const T {
41 return self.items[0..self.len];
4142 }
4243
43 pub fn at(l: *const Self, n: usize) T {
44 return l.toSliceConst()[n];
44 pub fn at(self: *const Self, n: usize) T {
45 return self.toSliceConst()[n];
46 }
47
48 /// Sets the value at index `i`, or returns `error.OutOfBounds` if
49 /// the index is not in range.
50 pub fn setOrError(self: *const Self, i: usize, item: *const T) !void {
51 if (i >= self.len) return error.OutOfBounds;
52 self.items[i] = item.*;
53 }
54
55 /// Sets the value at index `i`, asserting that the value is in range.
56 pub fn set(self: *const Self, i: usize, item: *const T) void {
57 assert(i < self.len);
58 self.items[i] = item.*;
4559 }
4660
4761 pub fn count(self: *const Self) usize {
......@@ -67,58 +81,58 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
6781 return result;
6882 }
6983
70 pub fn insert(l: *Self, n: usize, item: *const T) !void {
71 try l.ensureCapacity(l.len + 1);
72 l.len += 1;
84 pub fn insert(self: *Self, n: usize, item: *const T) !void {
85 try self.ensureCapacity(self.len + 1);
86 self.len += 1;
7387
74 mem.copy(T, l.items[n + 1 .. l.len], l.items[n .. l.len - 1]);
75 l.items[n] = item.*;
88 mem.copy(T, self.items[n + 1 .. self.len], self.items[n .. self.len - 1]);
89 self.items[n] = item.*;
7690 }
7791
78 pub fn insertSlice(l: *Self, n: usize, items: []align(A) const T) !void {
79 try l.ensureCapacity(l.len + items.len);
80 l.len += items.len;
92 pub fn insertSlice(self: *Self, n: usize, items: []align(A) const T) !void {
93 try self.ensureCapacity(self.len + items.len);
94 self.len += items.len;
8195
82 mem.copy(T, l.items[n + items.len .. l.len], l.items[n .. l.len - items.len]);
83 mem.copy(T, l.items[n .. n + items.len], items);
96 mem.copy(T, self.items[n + items.len .. self.len], self.items[n .. self.len - items.len]);
97 mem.copy(T, self.items[n .. n + items.len], items);
8498 }
8599
86 pub fn append(l: *Self, item: *const T) !void {
87 const new_item_ptr = try l.addOne();
100 pub fn append(self: *Self, item: *const T) !void {
101 const new_item_ptr = try self.addOne();
88102 new_item_ptr.* = item.*;
89103 }
90104
91 pub fn appendSlice(l: *Self, items: []align(A) const T) !void {
92 try l.ensureCapacity(l.len + items.len);
93 mem.copy(T, l.items[l.len..], items);
94 l.len += items.len;
105 pub fn appendSlice(self: *Self, items: []align(A) const T) !void {
106 try self.ensureCapacity(self.len + items.len);
107 mem.copy(T, self.items[self.len..], items);
108 self.len += items.len;
95109 }
96110
97 pub fn resize(l: *Self, new_len: usize) !void {
98 try l.ensureCapacity(new_len);
99 l.len = new_len;
111 pub fn resize(self: *Self, new_len: usize) !void {
112 try self.ensureCapacity(new_len);
113 self.len = new_len;
100114 }
101115
102 pub fn shrink(l: *Self, new_len: usize) void {
103 assert(new_len <= l.len);
104 l.len = new_len;
116 pub fn shrink(self: *Self, new_len: usize) void {
117 assert(new_len <= self.len);
118 self.len = new_len;
105119 }
106120
107 pub fn ensureCapacity(l: *Self, new_capacity: usize) !void {
108 var better_capacity = l.items.len;
121 pub fn ensureCapacity(self: *Self, new_capacity: usize) !void {
122 var better_capacity = self.items.len;
109123 if (better_capacity >= new_capacity) return;
110124 while (true) {
111125 better_capacity += better_capacity / 2 + 8;
112126 if (better_capacity >= new_capacity) break;
113127 }
114 l.items = try l.allocator.alignedRealloc(T, A, l.items, better_capacity);
128 self.items = try self.allocator.alignedRealloc(T, A, self.items, better_capacity);
115129 }
116130
117 pub fn addOne(l: *Self) !*T {
118 const new_length = l.len + 1;
119 try l.ensureCapacity(new_length);
120 const result = &l.items[l.len];
121 l.len = new_length;
131 pub fn addOne(self: *Self) !*T {
132 const new_length = self.len + 1;
133 try self.ensureCapacity(new_length);
134 const result = &self.items[self.len];
135 self.len = new_length;
122136 return result;
123137 }
124138
......@@ -159,9 +173,15 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
159173}
160174
161175test "basic ArrayList test" {
162 var list = ArrayList(i32).init(debug.global_allocator);
176 var bytes: [1024]u8 = undefined;
177 const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
178
179 var list = ArrayList(i32).init(allocator);
163180 defer list.deinit();
164181
182 // setting on empty list is out of bounds
183 assertError(list.setOrError(0, 1), error.OutOfBounds);
184
165185 {
166186 var i: usize = 0;
167187 while (i < 10) : (i += 1) {
......@@ -200,6 +220,16 @@ test "basic ArrayList test" {
200220
201221 list.appendSlice([]const i32{}) catch unreachable;
202222 assert(list.len == 9);
223
224 // can only set on indices < self.len
225 list.set(7, 33);
226 list.set(8, 42);
227
228 assertError(list.setOrError(9, 99), error.OutOfBounds);
229 assertError(list.setOrError(10, 123), error.OutOfBounds);
230
231 assert(list.pop() == 42);
232 assert(list.pop() == 33);
203233}
204234
205235test "iterator ArrayList test" {
......@@ -228,7 +258,7 @@ test "iterator ArrayList test" {
228258 }
229259
230260 it.reset();
231 assert(??it.next() == 1);
261 assert(it.next().? == 1);
232262}
233263
234264test "insert ArrayList test" {
std/atomic/queue.zig+17-8
......@@ -33,8 +33,8 @@ pub fn Queue(comptime T: type) type {
3333 pub fn get(self: *Self) ?*Node {
3434 var head = @atomicLoad(*Node, &self.head, AtomicOrder.SeqCst);
3535 while (true) {
36 const node = head.next ?? return null;
37 head = @cmpxchgWeak(*Node, &self.head, head, node, AtomicOrder.SeqCst, AtomicOrder.SeqCst) ?? return node;
36 const node = head.next orelse return null;
37 head = @cmpxchgWeak(*Node, &self.head, head, node, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse return node;
3838 }
3939 }
4040 };
......@@ -94,8 +94,18 @@ test "std.atomic.queue" {
9494 for (getters) |t|
9595 t.wait();
9696
97 std.debug.assert(context.put_sum == context.get_sum);
98 std.debug.assert(context.get_count == puts_per_thread * put_thread_count);
97 if (context.put_sum != context.get_sum) {
98 std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum);
99 }
100
101 if (context.get_count != puts_per_thread * put_thread_count) {
102 std.debug.panic(
103 "failure\nget_count:{} != puts_per_thread:{} * put_thread_count:{}",
104 context.get_count,
105 u32(puts_per_thread),
106 u32(put_thread_count),
107 );
108 }
99109}
100110
101111fn startPuts(ctx: *Context) u8 {
......@@ -114,15 +124,14 @@ fn startPuts(ctx: *Context) u8 {
114124
115125fn startGets(ctx: *Context) u8 {
116126 while (true) {
127 const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
128
117129 while (ctx.queue.get()) |node| {
118130 std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
119131 _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
120132 _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
121133 }
122134
123 if (@atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1) {
124 break;
125 }
135 if (last) return 0;
126136 }
127 return 0;
128137}
std/atomic/stack.zig+17-8
......@@ -28,14 +28,14 @@ pub fn Stack(comptime T: type) type {
2828 var root = @atomicLoad(?*Node, &self.root, AtomicOrder.SeqCst);
2929 while (true) {
3030 node.next = root;
31 root = @cmpxchgWeak(?*Node, &self.root, root, node, AtomicOrder.SeqCst, AtomicOrder.SeqCst) ?? break;
31 root = @cmpxchgWeak(?*Node, &self.root, root, node, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse break;
3232 }
3333 }
3434
3535 pub fn pop(self: *Self) ?*Node {
3636 var root = @atomicLoad(?*Node, &self.root, AtomicOrder.SeqCst);
3737 while (true) {
38 root = @cmpxchgWeak(?*Node, &self.root, root, (root ?? return null).next, AtomicOrder.SeqCst, AtomicOrder.SeqCst) ?? return root;
38 root = @cmpxchgWeak(?*Node, &self.root, root, (root orelse return null).next, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse return root;
3939 }
4040 }
4141
......@@ -97,8 +97,18 @@ test "std.atomic.stack" {
9797 for (getters) |t|
9898 t.wait();
9999
100 std.debug.assert(context.put_sum == context.get_sum);
101 std.debug.assert(context.get_count == puts_per_thread * put_thread_count);
100 if (context.put_sum != context.get_sum) {
101 std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum);
102 }
103
104 if (context.get_count != puts_per_thread * put_thread_count) {
105 std.debug.panic(
106 "failure\nget_count:{} != puts_per_thread:{} * put_thread_count:{}",
107 context.get_count,
108 u32(puts_per_thread),
109 u32(put_thread_count),
110 );
111 }
102112}
103113
104114fn startPuts(ctx: *Context) u8 {
......@@ -117,15 +127,14 @@ fn startPuts(ctx: *Context) u8 {
117127
118128fn startGets(ctx: *Context) u8 {
119129 while (true) {
130 const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
131
120132 while (ctx.stack.pop()) |node| {
121133 std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
122134 _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
123135 _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
124136 }
125137
126 if (@atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1) {
127 break;
128 }
138 if (last) return 0;
129139 }
130 return 0;
131140}
std/buf_map.zig+6-6
......@@ -19,7 +19,7 @@ pub const BufMap = struct {
1919 pub fn deinit(self: *const BufMap) void {
2020 var it = self.hash_map.iterator();
2121 while (true) {
22 const entry = it.next() ?? break;
22 const entry = it.next() orelse break;
2323 self.free(entry.key);
2424 self.free(entry.value);
2525 }
......@@ -37,12 +37,12 @@ pub const BufMap = struct {
3737 }
3838
3939 pub fn get(self: *const BufMap, key: []const u8) ?[]const u8 {
40 const entry = self.hash_map.get(key) ?? return null;
40 const entry = self.hash_map.get(key) orelse return null;
4141 return entry.value;
4242 }
4343
4444 pub fn delete(self: *BufMap, key: []const u8) void {
45 const entry = self.hash_map.remove(key) ?? return;
45 const entry = self.hash_map.remove(key) orelse return;
4646 self.free(entry.key);
4747 self.free(entry.value);
4848 }
......@@ -72,15 +72,15 @@ test "BufMap" {
7272 defer bufmap.deinit();
7373
7474 try bufmap.set("x", "1");
75 assert(mem.eql(u8, ??bufmap.get("x"), "1"));
75 assert(mem.eql(u8, bufmap.get("x").?, "1"));
7676 assert(1 == bufmap.count());
7777
7878 try bufmap.set("x", "2");
79 assert(mem.eql(u8, ??bufmap.get("x"), "2"));
79 assert(mem.eql(u8, bufmap.get("x").?, "2"));
8080 assert(1 == bufmap.count());
8181
8282 try bufmap.set("x", "3");
83 assert(mem.eql(u8, ??bufmap.get("x"), "3"));
83 assert(mem.eql(u8, bufmap.get("x").?, "3"));
8484 assert(1 == bufmap.count());
8585
8686 bufmap.delete("x");
std/buf_set.zig+2-2
......@@ -17,7 +17,7 @@ pub const BufSet = struct {
1717 pub fn deinit(self: *const BufSet) void {
1818 var it = self.hash_map.iterator();
1919 while (true) {
20 const entry = it.next() ?? break;
20 const entry = it.next() orelse break;
2121 self.free(entry.key);
2222 }
2323
......@@ -33,7 +33,7 @@ pub const BufSet = struct {
3333 }
3434
3535 pub fn delete(self: *BufSet, key: []const u8) void {
36 const entry = self.hash_map.remove(key) ?? return;
36 const entry = self.hash_map.remove(key) orelse return;
3737 self.free(entry.key);
3838 }
3939
std/buffer.zig+3-4
......@@ -28,7 +28,6 @@ pub const Buffer = struct {
2828 /// Must deinitialize with deinit.
2929 /// None of the other operations are valid until you do one of these:
3030 /// * ::replaceContents
31 /// * ::replaceContentsBuffer
3231 /// * ::resize
3332 pub fn initNull(allocator: *Allocator) Buffer {
3433 return Buffer{ .list = ArrayList(u8).init(allocator) };
......@@ -42,9 +41,9 @@ pub const Buffer = struct {
4241 /// Buffer takes ownership of the passed in slice. The slice must have been
4342 /// allocated with `allocator`.
4443 /// Must deinitialize with deinit.
45 pub fn fromOwnedSlice(allocator: *Allocator, slice: []u8) Buffer {
44 pub fn fromOwnedSlice(allocator: *Allocator, slice: []u8) !Buffer {
4645 var self = Buffer{ .list = ArrayList(u8).fromOwnedSlice(allocator, slice) };
47 self.list.append(0);
46 try self.list.append(0);
4847 return self;
4948 }
5049
......@@ -116,7 +115,7 @@ pub const Buffer = struct {
116115 return mem.eql(u8, self.list.items[start..l], m);
117116 }
118117
119 pub fn replaceContents(self: *const Buffer, m: []const u8) !void {
118 pub fn replaceContents(self: *Buffer, m: []const u8) !void {
120119 try self.resize(m.len);
121120 mem.copy(u8, self.list.toSlice(), m);
122121 }
std/build.zig+21-19
......@@ -136,7 +136,7 @@ pub const Builder = struct {
136136 }
137137
138138 pub fn setInstallPrefix(self: *Builder, maybe_prefix: ?[]const u8) void {
139 self.prefix = maybe_prefix ?? "/usr/local"; // TODO better default
139 self.prefix = maybe_prefix orelse "/usr/local"; // TODO better default
140140 self.lib_dir = os.path.join(self.allocator, self.prefix, "lib") catch unreachable;
141141 self.exe_dir = os.path.join(self.allocator, self.prefix, "bin") catch unreachable;
142142 }
......@@ -312,9 +312,9 @@ pub const Builder = struct {
312312 if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
313313 var it = mem.split(nix_cflags_compile, " ");
314314 while (true) {
315 const word = it.next() ?? break;
315 const word = it.next() orelse break;
316316 if (mem.eql(u8, word, "-isystem")) {
317 const include_path = it.next() ?? {
317 const include_path = it.next() orelse {
318318 warn("Expected argument after -isystem in NIX_CFLAGS_COMPILE\n");
319319 break;
320320 };
......@@ -330,9 +330,9 @@ pub const Builder = struct {
330330 if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| {
331331 var it = mem.split(nix_ldflags, " ");
332332 while (true) {
333 const word = it.next() ?? break;
333 const word = it.next() orelse break;
334334 if (mem.eql(u8, word, "-rpath")) {
335 const rpath = it.next() ?? {
335 const rpath = it.next() orelse {
336336 warn("Expected argument after -rpath in NIX_LDFLAGS\n");
337337 break;
338338 };
......@@ -362,7 +362,7 @@ pub const Builder = struct {
362362 }
363363 self.available_options_list.append(available_option) catch unreachable;
364364
365 const entry = self.user_input_options.get(name) ?? return null;
365 const entry = self.user_input_options.get(name) orelse return null;
366366 entry.value.used = true;
367367 switch (type_id) {
368368 TypeId.Bool => switch (entry.value.value) {
......@@ -416,9 +416,9 @@ pub const Builder = struct {
416416 pub fn standardReleaseOptions(self: *Builder) builtin.Mode {
417417 if (self.release_mode) |mode| return mode;
418418
419 const release_safe = self.option(bool, "release-safe", "optimizations on and safety on") ?? false;
420 const release_fast = self.option(bool, "release-fast", "optimizations on and safety off") ?? false;
421 const release_small = self.option(bool, "release-small", "size optimizations on and safety off") ?? false;
419 const release_safe = self.option(bool, "release-safe", "optimizations on and safety on") orelse false;
420 const release_fast = self.option(bool, "release-fast", "optimizations on and safety off") orelse false;
421 const release_small = self.option(bool, "release-small", "size optimizations on and safety off") orelse false;
422422
423423 const mode = if (release_safe and !release_fast and !release_small) builtin.Mode.ReleaseSafe else if (release_fast and !release_safe and !release_small) builtin.Mode.ReleaseFast else if (release_small and !release_fast and !release_safe) builtin.Mode.ReleaseSmall else if (!release_fast and !release_safe and !release_small) builtin.Mode.Debug else x: {
424424 warn("Multiple release modes (of -Drelease-safe, -Drelease-fast and -Drelease-small)");
......@@ -518,7 +518,7 @@ pub const Builder = struct {
518518 // make sure all args are used
519519 var it = self.user_input_options.iterator();
520520 while (true) {
521 const entry = it.next() ?? break;
521 const entry = it.next() orelse break;
522522 if (!entry.value.used) {
523523 warn("Invalid option: -D{}\n\n", entry.key);
524524 self.markInvalidUserInput();
......@@ -617,7 +617,7 @@ pub const Builder = struct {
617617 warn("cp {} {}\n", source_path, dest_path);
618618 }
619619
620 const dirname = os.path.dirname(dest_path);
620 const dirname = os.path.dirname(dest_path) orelse ".";
621621 const abs_source_path = self.pathFromRoot(source_path);
622622 os.makePath(self.allocator, dirname) catch |err| {
623623 warn("Unable to create path {}: {}\n", dirname, @errorName(err));
......@@ -1246,7 +1246,7 @@ pub const LibExeObjStep = struct {
12461246 {
12471247 var it = self.link_libs.iterator();
12481248 while (true) {
1249 const entry = it.next() ?? break;
1249 const entry = it.next() orelse break;
12501250 zig_args.append("--library") catch unreachable;
12511251 zig_args.append(entry.key) catch unreachable;
12521252 }
......@@ -1395,8 +1395,9 @@ pub const LibExeObjStep = struct {
13951395 cc_args.append(abs_source_file) catch unreachable;
13961396
13971397 const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;
1398 const cache_o_dir = os.path.dirname(cache_o_src);
1399 try builder.makePath(cache_o_dir);
1398 if (os.path.dirname(cache_o_src)) |cache_o_dir| {
1399 try builder.makePath(cache_o_dir);
1400 }
14001401 const cache_o_file = builder.fmt("{}{}", cache_o_src, self.target.oFileExt());
14011402 cc_args.append("-o") catch unreachable;
14021403 cc_args.append(builder.pathFromRoot(cache_o_file)) catch unreachable;
......@@ -1509,8 +1510,9 @@ pub const LibExeObjStep = struct {
15091510 cc_args.append(abs_source_file) catch unreachable;
15101511
15111512 const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;
1512 const cache_o_dir = os.path.dirname(cache_o_src);
1513 try builder.makePath(cache_o_dir);
1513 if (os.path.dirname(cache_o_src)) |cache_o_dir| {
1514 try builder.makePath(cache_o_dir);
1515 }
15141516 const cache_o_file = builder.fmt("{}{}", cache_o_src, self.target.oFileExt());
15151517 cc_args.append("-o") catch unreachable;
15161518 cc_args.append(builder.pathFromRoot(cache_o_file)) catch unreachable;
......@@ -1696,7 +1698,7 @@ pub const TestStep = struct {
16961698 {
16971699 var it = self.link_libs.iterator();
16981700 while (true) {
1699 const entry = it.next() ?? break;
1701 const entry = it.next() orelse break;
17001702 try zig_args.append("--library");
17011703 try zig_args.append(entry.key);
17021704 }
......@@ -1855,7 +1857,7 @@ pub const WriteFileStep = struct {
18551857 fn make(step: *Step) !void {
18561858 const self = @fieldParentPtr(WriteFileStep, "step", step);
18571859 const full_path = self.builder.pathFromRoot(self.file_path);
1858 const full_path_dir = os.path.dirname(full_path);
1860 const full_path_dir = os.path.dirname(full_path) orelse ".";
18591861 os.makePath(self.builder.allocator, full_path_dir) catch |err| {
18601862 warn("unable to make path {}: {}\n", full_path_dir, @errorName(err));
18611863 return err;
......@@ -1945,7 +1947,7 @@ pub const Step = struct {
19451947};
19461948
19471949fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void {
1948 const out_dir = os.path.dirname(output_path);
1950 const out_dir = os.path.dirname(output_path) orelse ".";
19491951 const out_basename = os.path.basename(output_path);
19501952 // sym link for libfoo.so.1 to libfoo.so.1.2.3
19511953 const major_only_path = os.path.join(allocator, out_dir, filename_major_only) catch unreachable;
std/c/index.zig+10-10
......@@ -20,11 +20,11 @@ pub extern "c" fn @"fstat$INODE64"(fd: c_int, buf: *Stat) c_int;
2020pub extern "c" fn lseek(fd: c_int, offset: isize, whence: c_int) isize;
2121pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int;
2222pub extern "c" fn raise(sig: c_int) c_int;
23pub extern "c" fn read(fd: c_int, buf: [*]c_void, nbyte: usize) isize;
23pub extern "c" fn read(fd: c_int, buf: *c_void, nbyte: usize) isize;
2424pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int;
25pub extern "c" fn write(fd: c_int, buf: [*]const c_void, nbyte: usize) isize;
26pub extern "c" fn mmap(addr: ?[*]c_void, len: usize, prot: c_int, flags: c_int, fd: c_int, offset: isize) ?[*]c_void;
27pub extern "c" fn munmap(addr: [*]c_void, len: usize) c_int;
25pub extern "c" fn write(fd: c_int, buf: *const c_void, nbyte: usize) isize;
26pub extern "c" fn mmap(addr: ?*c_void, len: usize, prot: c_int, flags: c_int, fd: c_int, offset: isize) ?*c_void;
27pub extern "c" fn munmap(addr: *c_void, len: usize) c_int;
2828pub extern "c" fn unlink(path: [*]const u8) c_int;
2929pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;
3030pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_int, options: c_int) c_int;
......@@ -48,15 +48,15 @@ pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
4848pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
4949pub extern "c" fn rmdir(path: [*]const u8) c_int;
5050
51pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?[*]c_void;
52pub extern "c" fn malloc(usize) ?[*]c_void;
53pub extern "c" fn realloc([*]c_void, usize) ?[*]c_void;
54pub extern "c" fn free([*]c_void) void;
55pub extern "c" fn posix_memalign(memptr: *[*]c_void, alignment: usize, size: usize) c_int;
51pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void;
52pub extern "c" fn malloc(usize) ?*c_void;
53pub extern "c" fn realloc(*c_void, usize) ?*c_void;
54pub extern "c" fn free(*c_void) void;
55pub extern "c" fn posix_memalign(memptr: **c_void, alignment: usize, size: usize) c_int;
5656
5757pub extern "pthread" fn pthread_create(noalias newthread: *pthread_t, noalias attr: ?*const pthread_attr_t, start_routine: extern fn (?*c_void) ?*c_void, noalias arg: ?*c_void) c_int;
5858pub extern "pthread" fn pthread_attr_init(attr: *pthread_attr_t) c_int;
59pub extern "pthread" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: [*]c_void, stacksize: usize) c_int;
59pub extern "pthread" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;
6060pub extern "pthread" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;
6161pub extern "pthread" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;
6262
std/debug/index.zig+20-10
......@@ -88,6 +88,16 @@ pub fn assert(ok: bool) void {
8888 }
8989}
9090
91/// TODO: add `==` operator for `error_union == error_set`, and then
92/// remove this function
93pub fn assertError(value: var, expected_error: error) void {
94 if (value) {
95 @panic("expected error");
96 } else |actual_error| {
97 assert(actual_error == expected_error);
98 }
99}
100
91101/// Call this function when you want to panic if the condition is not true.
92102/// If `ok` is `false`, this function will panic in every release mode.
93103pub fn assertOrPanic(ok: bool) void {
......@@ -198,7 +208,7 @@ fn printSourceAtAddress(debug_info: *ElfStackTrace, out_stream: var, address: us
198208 .name = "???",
199209 .address = address,
200210 };
201 const symbol = debug_info.symbol_table.search(address) ?? &unknown;
211 const symbol = debug_info.symbol_table.search(address) orelse &unknown;
202212 try out_stream.print(WHITE ++ "{}" ++ RESET ++ ": " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n", symbol.name, address);
203213 },
204214 else => {
......@@ -258,10 +268,10 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !*ElfStackTrace {
258268 try st.elf.openFile(allocator, &st.self_exe_file);
259269 errdefer st.elf.close();
260270
261 st.debug_info = (try st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
262 st.debug_abbrev = (try st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
263 st.debug_str = (try st.elf.findSection(".debug_str")) ?? return error.MissingDebugInfo;
264 st.debug_line = (try st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
271 st.debug_info = (try st.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo;
272 st.debug_abbrev = (try st.elf.findSection(".debug_abbrev")) orelse return error.MissingDebugInfo;
273 st.debug_str = (try st.elf.findSection(".debug_str")) orelse return error.MissingDebugInfo;
274 st.debug_line = (try st.elf.findSection(".debug_line")) orelse return error.MissingDebugInfo;
265275 st.debug_ranges = (try st.elf.findSection(".debug_ranges"));
266276 try scanAllCompileUnits(st);
267277 return st;
......@@ -433,7 +443,7 @@ const Die = struct {
433443 }
434444
435445 fn getAttrAddr(self: *const Die, id: u64) !u64 {
436 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
446 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
437447 return switch (form_value.*) {
438448 FormValue.Address => |value| value,
439449 else => error.InvalidDebugInfo,
......@@ -441,7 +451,7 @@ const Die = struct {
441451 }
442452
443453 fn getAttrSecOffset(self: *const Die, id: u64) !u64 {
444 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
454 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
445455 return switch (form_value.*) {
446456 FormValue.Const => |value| value.asUnsignedLe(),
447457 FormValue.SecOffset => |value| value,
......@@ -450,7 +460,7 @@ const Die = struct {
450460 }
451461
452462 fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
453 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
463 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
454464 return switch (form_value.*) {
455465 FormValue.Const => |value| value.asUnsignedLe(),
456466 else => error.InvalidDebugInfo,
......@@ -458,7 +468,7 @@ const Die = struct {
458468 }
459469
460470 fn getAttrString(self: *const Die, st: *ElfStackTrace, id: u64) ![]u8 {
461 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
471 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
462472 return switch (form_value.*) {
463473 FormValue.String => |value| value,
464474 FormValue.StrPtr => |offset| getString(st, offset),
......@@ -738,7 +748,7 @@ fn parseDie(st: *ElfStackTrace, abbrev_table: *const AbbrevTable, is_64: bool) !
738748 var in_file_stream = io.FileInStream.init(in_file);
739749 const in_stream = &in_file_stream.stream;
740750 const abbrev_code = try readULeb128(in_stream);
741 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;
751 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
742752
743753 var result = Die{
744754 .tag_id = table_entry.tag_id,
std/event.zig+2-2
......@@ -40,9 +40,9 @@ pub const TcpServer = struct {
4040 self.listen_address = std.net.Address.initPosix(try std.os.posixGetSockName(self.sockfd));
4141
4242 self.accept_coro = try async<self.loop.allocator> TcpServer.handler(self);
43 errdefer cancel ??self.accept_coro;
43 errdefer cancel self.accept_coro.?;
4444
45 try self.loop.addFd(self.sockfd, ??self.accept_coro);
45 try self.loop.addFd(self.sockfd, self.accept_coro.?);
4646 errdefer self.loop.removeFd(self.sockfd);
4747 }
4848
std/fmt/index.zig+44-20
......@@ -97,7 +97,11 @@ pub fn formatType(
9797 output: fn (@typeOf(context), []const u8) Errors!void,
9898) Errors!void {
9999 const T = @typeOf(value);
100 switch (@typeId(T)) {
100 if (T == error) {
101 try output(context, "error.");
102 return output(context, @errorName(value));
103 }
104 switch (@typeInfo(T)) {
101105 builtin.TypeId.Int, builtin.TypeId.Float => {
102106 return formatValue(value, fmt, context, Errors, output);
103107 },
......@@ -107,7 +111,7 @@ pub fn formatType(
107111 builtin.TypeId.Bool => {
108112 return output(context, if (value) "true" else "false");
109113 },
110 builtin.TypeId.Nullable => {
114 builtin.TypeId.Optional => {
111115 if (value) |payload| {
112116 return formatType(payload, fmt, context, Errors, output);
113117 } else {
......@@ -125,12 +129,13 @@ pub fn formatType(
125129 try output(context, "error.");
126130 return output(context, @errorName(value));
127131 },
128 builtin.TypeId.Pointer => {
129 switch (@typeId(T.Child)) {
130 builtin.TypeId.Array => {
131 if (T.Child.Child == u8) {
132 builtin.TypeId.Pointer => |ptr_info| switch (ptr_info.size) {
133 builtin.TypeInfo.Pointer.Size.One => switch (@typeInfo(ptr_info.child)) {
134 builtin.TypeId.Array => |info| {
135 if (info.child == u8) {
132136 return formatText(value, fmt, context, Errors, output);
133137 }
138 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
134139 },
135140 builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
136141 const has_cust_fmt = comptime cf: {
......@@ -154,14 +159,24 @@ pub fn formatType(
154159 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
155160 },
156161 else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),
157 }
158 },
159 else => if (@canImplicitCast([]const u8, value)) {
160 const casted_value = ([]const u8)(value);
161 return output(context, casted_value);
162 } else {
163 @compileError("Unable to format type '" ++ @typeName(T) ++ "'");
162 },
163 builtin.TypeInfo.Pointer.Size.Many => {
164 if (ptr_info.child == u8) {
165 //This is a bit of a hack, but it made more sense to
166 // do this check here than have formatText do it
167 if (fmt[0] == 's') {
168 const len = std.cstr.len(value);
169 return formatText(value[0..len], fmt, context, Errors, output);
170 }
171 }
172 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
173 },
174 builtin.TypeInfo.Pointer.Size.Slice => {
175 const casted_value = ([]const u8)(value);
176 return output(context, casted_value);
177 },
164178 },
179 else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
165180 }
166181}
167182
......@@ -293,7 +308,7 @@ pub fn formatBuf(
293308 var leftover_padding = if (width > buf.len) (width - buf.len) else return;
294309 const pad_byte: u8 = ' ';
295310 while (leftover_padding > 0) : (leftover_padding -= 1) {
296 try output(context, (&pad_byte)[0..1]);
311 try output(context, (*[1]u8)(&pad_byte)[0..1]);
297312 }
298313}
299314
......@@ -552,14 +567,19 @@ pub fn formatBytes(
552567 return output(context, "0B");
553568 }
554569
555 const mags = " KMGTPEZY";
570 const mags_si = " kMGTPEZY";
571 const mags_iec = " KMGTPEZY";
556572 const magnitude = switch (radix) {
557 1000 => math.min(math.log2(value) / comptime math.log2(1000), mags.len - 1),
558 1024 => math.min(math.log2(value) / 10, mags.len - 1),
573 1000 => math.min(math.log2(value) / comptime math.log2(1000), mags_si.len - 1),
574 1024 => math.min(math.log2(value) / 10, mags_iec.len - 1),
559575 else => unreachable,
560576 };
561577 const new_value = f64(value) / math.pow(f64, f64(radix), f64(magnitude));
562 const suffix = mags[magnitude];
578 const suffix = switch (radix) {
579 1000 => mags_si[magnitude],
580 1024 => mags_iec[magnitude],
581 else => unreachable,
582 };
563583
564584 try formatFloatDecimal(new_value, width, context, Errors, output);
565585
......@@ -807,11 +827,11 @@ test "parse unsigned comptime" {
807827test "fmt.format" {
808828 {
809829 const value: ?i32 = 1234;
810 try testFmt("nullable: 1234\n", "nullable: {}\n", value);
830 try testFmt("optional: 1234\n", "optional: {}\n", value);
811831 }
812832 {
813833 const value: ?i32 = null;
814 try testFmt("nullable: null\n", "nullable: {}\n", value);
834 try testFmt("optional: null\n", "optional: {}\n", value);
815835 }
816836 {
817837 const value: error!i32 = 1234;
......@@ -829,6 +849,10 @@ test "fmt.format" {
829849 const value: u8 = 'a';
830850 try testFmt("u8: a\n", "u8: {c}\n", value);
831851 }
852 try testFmt("buf: Test \n", "buf: {s5}\n", "Test");
853 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
854 try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");
855 try testFmt("cstr: Test C \n", "cstr: {s10}\n", c"Test C");
832856 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
833857 try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));
834858 {
std/hash_map.zig+4-4
......@@ -265,11 +265,11 @@ test "basic hash map usage" {
265265 assert((map.put(4, 44) catch unreachable) == null);
266266 assert((map.put(5, 55) catch unreachable) == null);
267267
268 assert(??(map.put(5, 66) catch unreachable) == 55);
269 assert(??(map.put(5, 55) catch unreachable) == 66);
268 assert((map.put(5, 66) catch unreachable).? == 55);
269 assert((map.put(5, 55) catch unreachable).? == 66);
270270
271271 assert(map.contains(2));
272 assert((??map.get(2)).value == 22);
272 assert(map.get(2).?.value == 22);
273273 _ = map.remove(2);
274274 assert(map.remove(2) == null);
275275 assert(map.get(2) == null);
......@@ -317,7 +317,7 @@ test "iterator hash map" {
317317 }
318318
319319 it.reset();
320 var entry = ??it.next();
320 var entry = it.next().?;
321321 assert(entry.key == keys[0]);
322322 assert(entry.value == values[0]);
323323}
std/heap.zig+10-10
......@@ -22,7 +22,7 @@ fn cAlloc(self: *Allocator, n: usize, alignment: u29) ![]u8 {
2222}
2323
2424fn cRealloc(self: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
25 const old_ptr = @ptrCast([*]c_void, old_mem.ptr);
25 const old_ptr = @ptrCast(*c_void, old_mem.ptr);
2626 if (c.realloc(old_ptr, new_size)) |buf| {
2727 return @ptrCast([*]u8, buf)[0..new_size];
2828 } else if (new_size <= old_mem.len) {
......@@ -33,7 +33,7 @@ fn cRealloc(self: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![
3333}
3434
3535fn cFree(self: *Allocator, old_mem: []u8) void {
36 const old_ptr = @ptrCast([*]c_void, old_mem.ptr);
36 const old_ptr = @ptrCast(*c_void, old_mem.ptr);
3737 c.free(old_ptr);
3838}
3939
......@@ -97,12 +97,12 @@ pub const DirectAllocator = struct {
9797 },
9898 Os.windows => {
9999 const amt = n + alignment + @sizeOf(usize);
100 const heap_handle = self.heap_handle ?? blk: {
101 const hh = os.windows.HeapCreate(os.windows.HEAP_NO_SERIALIZE, amt, 0) ?? return error.OutOfMemory;
100 const heap_handle = self.heap_handle orelse blk: {
101 const hh = os.windows.HeapCreate(os.windows.HEAP_NO_SERIALIZE, amt, 0) orelse return error.OutOfMemory;
102102 self.heap_handle = hh;
103103 break :blk hh;
104104 };
105 const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) ?? return error.OutOfMemory;
105 const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) orelse return error.OutOfMemory;
106106 const root_addr = @ptrToInt(ptr);
107107 const rem = @rem(root_addr, alignment);
108108 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
......@@ -140,9 +140,9 @@ pub const DirectAllocator = struct {
140140 const old_adjusted_addr = @ptrToInt(old_mem.ptr);
141141 const old_record_addr = old_adjusted_addr + old_mem.len;
142142 const root_addr = @intToPtr(*align(1) usize, old_record_addr).*;
143 const old_ptr = @intToPtr([*]c_void, root_addr);
143 const old_ptr = @intToPtr(*c_void, root_addr);
144144 const amt = new_size + alignment + @sizeOf(usize);
145 const new_ptr = os.windows.HeapReAlloc(??self.heap_handle, 0, old_ptr, amt) ?? blk: {
145 const new_ptr = os.windows.HeapReAlloc(self.heap_handle.?, 0, old_ptr, amt) orelse blk: {
146146 if (new_size > old_mem.len) return error.OutOfMemory;
147147 const new_record_addr = old_record_addr - new_size + old_mem.len;
148148 @intToPtr(*align(1) usize, new_record_addr).* = root_addr;
......@@ -170,8 +170,8 @@ pub const DirectAllocator = struct {
170170 Os.windows => {
171171 const record_addr = @ptrToInt(bytes.ptr) + bytes.len;
172172 const root_addr = @intToPtr(*align(1) usize, record_addr).*;
173 const ptr = @intToPtr([*]c_void, root_addr);
174 _ = os.windows.HeapFree(??self.heap_handle, 0, ptr);
173 const ptr = @intToPtr(*c_void, root_addr);
174 _ = os.windows.HeapFree(self.heap_handle.?, 0, ptr);
175175 },
176176 else => @compileError("Unsupported OS"),
177177 }
......@@ -343,7 +343,7 @@ pub const ThreadSafeFixedBufferAllocator = struct {
343343 if (new_end_index > self.buffer.len) {
344344 return error.OutOfMemory;
345345 }
346 end_index = @cmpxchgWeak(usize, &self.end_index, end_index, new_end_index, builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) ?? return self.buffer[adjusted_index..new_end_index];
346 end_index = @cmpxchgWeak(usize, &self.end_index, end_index, new_end_index, builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) orelse return self.buffer[adjusted_index..new_end_index];
347347 }
348348 }
349349
std/json.zig+177-88
......@@ -3,6 +3,7 @@
33// https://tools.ietf.org/html/rfc8259
44
55const std = @import("index.zig");
6const debug = std.debug;
67const mem = std.mem;
78
89const u1 = @IntType(false, 1);
......@@ -86,7 +87,9 @@ pub const Token = struct {
8687// parsing state requires ~40-50 bytes of stack space.
8788//
8889// Conforms strictly to RFC8529.
89pub const StreamingJsonParser = struct {
90//
91// For a non-byte based wrapper, consider using TokenStream instead.
92pub const StreamingParser = struct {
9093 // Current state
9194 state: State,
9295 // How many bytes we have counted for the current token
......@@ -109,13 +112,13 @@ pub const StreamingJsonParser = struct {
109112 const array_bit = 1;
110113 const max_stack_size = @maxValue(u8);
111114
112 pub fn init() StreamingJsonParser {
113 var p: StreamingJsonParser = undefined;
115 pub fn init() StreamingParser {
116 var p: StreamingParser = undefined;
114117 p.reset();
115118 return p;
116119 }
117120
118 pub fn reset(p: *StreamingJsonParser) void {
121 pub fn reset(p: *StreamingParser) void {
119122 p.state = State.TopLevelBegin;
120123 p.count = 0;
121124 // Set before ever read in main transition function
......@@ -175,7 +178,7 @@ pub const StreamingJsonParser = struct {
175178
176179 // Only call this function to generate array/object final state.
177180 pub fn fromInt(x: var) State {
178 std.debug.assert(x == 0 or x == 1);
181 debug.assert(x == 0 or x == 1);
179182 const T = @TagType(State);
180183 return State(T(x));
181184 }
......@@ -205,7 +208,7 @@ pub const StreamingJsonParser = struct {
205208 // tokens. token2 is always null if token1 is null.
206209 //
207210 // There is currently no error recovery on a bad stream.
208 pub fn feed(p: *StreamingJsonParser, c: u8, token1: *?Token, token2: *?Token) Error!void {
211 pub fn feed(p: *StreamingParser, c: u8, token1: *?Token, token2: *?Token) Error!void {
209212 token1.* = null;
210213 token2.* = null;
211214 p.count += 1;
......@@ -217,7 +220,7 @@ pub const StreamingJsonParser = struct {
217220 }
218221
219222 // Perform a single transition on the state machine and return any possible token.
220 fn transition(p: *StreamingJsonParser, c: u8, token: *?Token) Error!bool {
223 fn transition(p: *StreamingParser, c: u8, token: *?Token) Error!bool {
221224 switch (p.state) {
222225 State.TopLevelBegin => switch (c) {
223226 '{' => {
......@@ -321,7 +324,9 @@ pub const StreamingJsonParser = struct {
321324 p.complete = true;
322325 p.state = State.TopLevelEnd;
323326 },
324 else => {},
327 else => {
328 p.state = State.ValueEnd;
329 },
325330 }
326331
327332 token.* = Token.initMarker(Token.Id.ObjectEnd);
......@@ -345,7 +350,9 @@ pub const StreamingJsonParser = struct {
345350 p.complete = true;
346351 p.state = State.TopLevelEnd;
347352 },
348 else => {},
353 else => {
354 p.state = State.ValueEnd;
355 },
349356 }
350357
351358 token.* = Token.initMarker(Token.Id.ArrayEnd);
......@@ -852,16 +859,122 @@ pub const StreamingJsonParser = struct {
852859 }
853860};
854861
862// A small wrapper over a StreamingParser for full slices. Returns a stream of json Tokens.
863pub const TokenStream = struct {
864 i: usize,
865 slice: []const u8,
866 parser: StreamingParser,
867 token: ?Token,
868
869 pub fn init(slice: []const u8) TokenStream {
870 return TokenStream{
871 .i = 0,
872 .slice = slice,
873 .parser = StreamingParser.init(),
874 .token = null,
875 };
876 }
877
878 pub fn next(self: *TokenStream) !?Token {
879 if (self.token) |token| {
880 self.token = null;
881 return token;
882 }
883
884 var t1: ?Token = undefined;
885 var t2: ?Token = undefined;
886
887 while (self.i < self.slice.len) {
888 try self.parser.feed(self.slice[self.i], &t1, &t2);
889 self.i += 1;
890
891 if (t1) |token| {
892 self.token = t2;
893 return token;
894 }
895 }
896
897 if (self.i > self.slice.len) {
898 try self.parser.feed(' ', &t1, &t2);
899 self.i += 1;
900
901 if (t1) |token| {
902 return token;
903 }
904 }
905
906 return null;
907 }
908};
909
910fn checkNext(p: *TokenStream, id: Token.Id) void {
911 const token = (p.next() catch unreachable).?;
912 debug.assert(token.id == id);
913}
914
915test "token" {
916 const s =
917 \\{
918 \\ "Image": {
919 \\ "Width": 800,
920 \\ "Height": 600,
921 \\ "Title": "View from 15th Floor",
922 \\ "Thumbnail": {
923 \\ "Url": "http://www.example.com/image/481989943",
924 \\ "Height": 125,
925 \\ "Width": 100
926 \\ },
927 \\ "Animated" : false,
928 \\ "IDs": [116, 943, 234, 38793]
929 \\ }
930 \\}
931 ;
932
933 var p = TokenStream.init(s);
934
935 checkNext(&p, Token.Id.ObjectBegin);
936 checkNext(&p, Token.Id.String); // Image
937 checkNext(&p, Token.Id.ObjectBegin);
938 checkNext(&p, Token.Id.String); // Width
939 checkNext(&p, Token.Id.Number);
940 checkNext(&p, Token.Id.String); // Height
941 checkNext(&p, Token.Id.Number);
942 checkNext(&p, Token.Id.String); // Title
943 checkNext(&p, Token.Id.String);
944 checkNext(&p, Token.Id.String); // Thumbnail
945 checkNext(&p, Token.Id.ObjectBegin);
946 checkNext(&p, Token.Id.String); // Url
947 checkNext(&p, Token.Id.String);
948 checkNext(&p, Token.Id.String); // Height
949 checkNext(&p, Token.Id.Number);
950 checkNext(&p, Token.Id.String); // Width
951 checkNext(&p, Token.Id.Number);
952 checkNext(&p, Token.Id.ObjectEnd);
953 checkNext(&p, Token.Id.String); // Animated
954 checkNext(&p, Token.Id.False);
955 checkNext(&p, Token.Id.String); // IDs
956 checkNext(&p, Token.Id.ArrayBegin);
957 checkNext(&p, Token.Id.Number);
958 checkNext(&p, Token.Id.Number);
959 checkNext(&p, Token.Id.Number);
960 checkNext(&p, Token.Id.Number);
961 checkNext(&p, Token.Id.ArrayEnd);
962 checkNext(&p, Token.Id.ObjectEnd);
963 checkNext(&p, Token.Id.ObjectEnd);
964
965 debug.assert((try p.next()) == null);
966}
967
855968// Validate a JSON string. This does not limit number precision so a decoder may not necessarily
856969// be able to decode the string even if this returns true.
857970pub fn validate(s: []const u8) bool {
858 var p = StreamingJsonParser.init();
971 var p = StreamingParser.init();
859972
860973 for (s) |c, i| {
861974 var token1: ?Token = undefined;
862975 var token2: ?Token = undefined;
863976
864 p.feed(c, *token1, *token2) catch |err| {
977 p.feed(c, &token1, &token2) catch |err| {
865978 return false;
866979 };
867980 }
......@@ -869,6 +982,10 @@ pub fn validate(s: []const u8) bool {
869982 return p.complete;
870983}
871984
985test "json validate" {
986 debug.assert(validate("{}"));
987}
988
872989const Allocator = std.mem.Allocator;
873990const ArenaAllocator = std.heap.ArenaAllocator;
874991const ArrayList = std.ArrayList;
......@@ -897,46 +1014,46 @@ pub const Value = union(enum) {
8971014 pub fn dump(self: *const Value) void {
8981015 switch (self.*) {
8991016 Value.Null => {
900 std.debug.warn("null");
1017 debug.warn("null");
9011018 },
9021019 Value.Bool => |inner| {
903 std.debug.warn("{}", inner);
1020 debug.warn("{}", inner);
9041021 },
9051022 Value.Integer => |inner| {
906 std.debug.warn("{}", inner);
1023 debug.warn("{}", inner);
9071024 },
9081025 Value.Float => |inner| {
909 std.debug.warn("{.5}", inner);
1026 debug.warn("{.5}", inner);
9101027 },
9111028 Value.String => |inner| {
912 std.debug.warn("\"{}\"", inner);
1029 debug.warn("\"{}\"", inner);
9131030 },
9141031 Value.Array => |inner| {
9151032 var not_first = false;
916 std.debug.warn("[");
1033 debug.warn("[");
9171034 for (inner.toSliceConst()) |value| {
9181035 if (not_first) {
919 std.debug.warn(",");
1036 debug.warn(",");
9201037 }
9211038 not_first = true;
9221039 value.dump();
9231040 }
924 std.debug.warn("]");
1041 debug.warn("]");
9251042 },
9261043 Value.Object => |inner| {
9271044 var not_first = false;
928 std.debug.warn("{{");
1045 debug.warn("{{");
9291046 var it = inner.iterator();
9301047
9311048 while (it.next()) |entry| {
9321049 if (not_first) {
933 std.debug.warn(",");
1050 debug.warn(",");
9341051 }
9351052 not_first = true;
936 std.debug.warn("\"{}\":", entry.key);
1053 debug.warn("\"{}\":", entry.key);
9371054 entry.value.dump();
9381055 }
939 std.debug.warn("}}");
1056 debug.warn("}}");
9401057 },
9411058 }
9421059 }
......@@ -952,53 +1069,53 @@ pub const Value = union(enum) {
9521069 fn dumpIndentLevel(self: *const Value, indent: usize, level: usize) void {
9531070 switch (self.*) {
9541071 Value.Null => {
955 std.debug.warn("null");
1072 debug.warn("null");
9561073 },
9571074 Value.Bool => |inner| {
958 std.debug.warn("{}", inner);
1075 debug.warn("{}", inner);
9591076 },
9601077 Value.Integer => |inner| {
961 std.debug.warn("{}", inner);
1078 debug.warn("{}", inner);
9621079 },
9631080 Value.Float => |inner| {
964 std.debug.warn("{.5}", inner);
1081 debug.warn("{.5}", inner);
9651082 },
9661083 Value.String => |inner| {
967 std.debug.warn("\"{}\"", inner);
1084 debug.warn("\"{}\"", inner);
9681085 },
9691086 Value.Array => |inner| {
9701087 var not_first = false;
971 std.debug.warn("[\n");
1088 debug.warn("[\n");
9721089
9731090 for (inner.toSliceConst()) |value| {
9741091 if (not_first) {
975 std.debug.warn(",\n");
1092 debug.warn(",\n");
9761093 }
9771094 not_first = true;
9781095 padSpace(level + indent);
9791096 value.dumpIndentLevel(indent, level + indent);
9801097 }
981 std.debug.warn("\n");
1098 debug.warn("\n");
9821099 padSpace(level);
983 std.debug.warn("]");
1100 debug.warn("]");
9841101 },
9851102 Value.Object => |inner| {
9861103 var not_first = false;
987 std.debug.warn("{{\n");
1104 debug.warn("{{\n");
9881105 var it = inner.iterator();
9891106
9901107 while (it.next()) |entry| {
9911108 if (not_first) {
992 std.debug.warn(",\n");
1109 debug.warn(",\n");
9931110 }
9941111 not_first = true;
9951112 padSpace(level + indent);
996 std.debug.warn("\"{}\": ", entry.key);
1113 debug.warn("\"{}\": ", entry.key);
9971114 entry.value.dumpIndentLevel(indent, level + indent);
9981115 }
999 std.debug.warn("\n");
1116 debug.warn("\n");
10001117 padSpace(level);
1001 std.debug.warn("}}");
1118 debug.warn("}}");
10021119 },
10031120 }
10041121 }
......@@ -1006,13 +1123,13 @@ pub const Value = union(enum) {
10061123 fn padSpace(indent: usize) void {
10071124 var i: usize = 0;
10081125 while (i < indent) : (i += 1) {
1009 std.debug.warn(" ");
1126 debug.warn(" ");
10101127 }
10111128 }
10121129};
10131130
10141131// A non-stream JSON parser which constructs a tree of Value's.
1015pub const JsonParser = struct {
1132pub const Parser = struct {
10161133 allocator: *Allocator,
10171134 state: State,
10181135 copy_strings: bool,
......@@ -1026,8 +1143,8 @@ pub const JsonParser = struct {
10261143 Simple,
10271144 };
10281145
1029 pub fn init(allocator: *Allocator, copy_strings: bool) JsonParser {
1030 return JsonParser{
1146 pub fn init(allocator: *Allocator, copy_strings: bool) Parser {
1147 return Parser{
10311148 .allocator = allocator,
10321149 .state = State.Simple,
10331150 .copy_strings = copy_strings,
......@@ -1035,52 +1152,26 @@ pub const JsonParser = struct {
10351152 };
10361153 }
10371154
1038 pub fn deinit(p: *JsonParser) void {
1155 pub fn deinit(p: *Parser) void {
10391156 p.stack.deinit();
10401157 }
10411158
1042 pub fn reset(p: *JsonParser) void {
1159 pub fn reset(p: *Parser) void {
10431160 p.state = State.Simple;
10441161 p.stack.shrink(0);
10451162 }
10461163
1047 pub fn parse(p: *JsonParser, input: []const u8) !ValueTree {
1048 var mp = StreamingJsonParser.init();
1164 pub fn parse(p: *Parser, input: []const u8) !ValueTree {
1165 var s = TokenStream.init(input);
10491166
10501167 var arena = ArenaAllocator.init(p.allocator);
10511168 errdefer arena.deinit();
10521169
1053 for (input) |c, i| {
1054 var mt1: ?Token = undefined;
1055 var mt2: ?Token = undefined;
1056
1057 try mp.feed(c, &mt1, &mt2);
1058 if (mt1) |t1| {
1059 try p.transition(&arena.allocator, input, i, t1);
1060
1061 if (mt2) |t2| {
1062 try p.transition(&arena.allocator, input, i, t2);
1063 }
1064 }
1065 }
1066
1067 // Handle top-level lonely number values.
1068 {
1069 const i = input.len;
1070 var mt1: ?Token = undefined;
1071 var mt2: ?Token = undefined;
1072
1073 try mp.feed(' ', &mt1, &mt2);
1074 if (mt1) |t1| {
1075 try p.transition(&arena.allocator, input, i, t1);
1076 }
1077 }
1078
1079 if (!mp.complete) {
1080 return error.IncompleteJsonInput;
1170 while (try s.next()) |token| {
1171 try p.transition(&arena.allocator, input, s.i - 1, token);
10811172 }
10821173
1083 std.debug.assert(p.stack.len == 1);
1174 debug.assert(p.stack.len == 1);
10841175
10851176 return ValueTree{
10861177 .arena = arena,
......@@ -1090,7 +1181,7 @@ pub const JsonParser = struct {
10901181
10911182 // Even though p.allocator exists, we take an explicit allocator so that allocation state
10921183 // can be cleaned up on error correctly during a `parse` on call.
1093 fn transition(p: *JsonParser, allocator: *Allocator, input: []const u8, i: usize, token: *const Token) !void {
1184 fn transition(p: *Parser, allocator: *Allocator, input: []const u8, i: usize, token: *const Token) !void {
10941185 switch (p.state) {
10951186 State.ObjectKey => switch (token.id) {
10961187 Token.Id.ObjectEnd => {
......@@ -1147,7 +1238,7 @@ pub const JsonParser = struct {
11471238 _ = p.stack.pop();
11481239 p.state = State.ObjectKey;
11491240 },
1150 else => {
1241 Token.Id.ObjectEnd, Token.Id.ArrayEnd => {
11511242 unreachable;
11521243 },
11531244 }
......@@ -1187,7 +1278,7 @@ pub const JsonParser = struct {
11871278 Token.Id.Null => {
11881279 try array.append(Value.Null);
11891280 },
1190 else => {
1281 Token.Id.ObjectEnd => {
11911282 unreachable;
11921283 },
11931284 }
......@@ -1223,7 +1314,7 @@ pub const JsonParser = struct {
12231314 }
12241315 }
12251316
1226 fn pushToParent(p: *JsonParser, value: *const Value) !void {
1317 fn pushToParent(p: *Parser, value: *const Value) !void {
12271318 switch (p.stack.at(p.stack.len - 1)) {
12281319 // Object Parent -> [ ..., object, <key>, value ]
12291320 Value.String => |key| {
......@@ -1244,14 +1335,14 @@ pub const JsonParser = struct {
12441335 }
12451336 }
12461337
1247 fn parseString(p: *JsonParser, allocator: *Allocator, token: *const Token, input: []const u8, i: usize) !Value {
1338 fn parseString(p: *Parser, allocator: *Allocator, token: *const Token, input: []const u8, i: usize) !Value {
12481339 // TODO: We don't strictly have to copy values which do not contain any escape
12491340 // characters if flagged with the option.
12501341 const slice = token.slice(input, i);
12511342 return Value{ .String = try mem.dupe(p.allocator, u8, slice) };
12521343 }
12531344
1254 fn parseNumber(p: *JsonParser, token: *const Token, input: []const u8, i: usize) !Value {
1345 fn parseNumber(p: *Parser, token: *const Token, input: []const u8, i: usize) !Value {
12551346 return if (token.number_is_integer)
12561347 Value{ .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) }
12571348 else
......@@ -1259,10 +1350,8 @@ pub const JsonParser = struct {
12591350 }
12601351};
12611352
1262const debug = std.debug;
1263
12641353test "json parser dynamic" {
1265 var p = JsonParser.init(std.debug.global_allocator, false);
1354 var p = Parser.init(debug.global_allocator, false);
12661355 defer p.deinit();
12671356
12681357 const s =
......@@ -1287,17 +1376,17 @@ test "json parser dynamic" {
12871376
12881377 var root = tree.root;
12891378
1290 var image = (??root.Object.get("Image")).value;
1379 var image = root.Object.get("Image").?.value;
12911380
1292 const width = (??image.Object.get("Width")).value;
1381 const width = image.Object.get("Width").?.value;
12931382 debug.assert(width.Integer == 800);
12941383
1295 const height = (??image.Object.get("Height")).value;
1384 const height = image.Object.get("Height").?.value;
12961385 debug.assert(height.Integer == 600);
12971386
1298 const title = (??image.Object.get("Title")).value;
1387 const title = image.Object.get("Title").?.value;
12991388 debug.assert(mem.eql(u8, title.String, "View from 15th Floor"));
13001389
1301 const animated = (??image.Object.get("Animated")).value;
1390 const animated = image.Object.get("Animated").?.value;
13021391 debug.assert(animated.Bool == false);
13031392}
std/json_test.zig+10
......@@ -17,6 +17,16 @@ fn any(comptime s: []const u8) void {
1717 std.debug.assert(true);
1818}
1919
20////////////////////////////////////////////////////////////////////////////////////////////////////
21//
22// Additional tests not part of test JSONTestSuite.
23
24test "y_trailing_comma_after_empty" {
25 ok(
26 \\{"1":[],"2":{},"3":"4"}
27 );
28}
29
2030////////////////////////////////////////////////////////////////////////////////////////////////////
2131
2232test "y_array_arraysWithSpaces" {
std/linked_list.zig+6-6
......@@ -169,7 +169,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
169169 /// Returns:
170170 /// A pointer to the last node in the list.
171171 pub fn pop(list: *Self) ?*Node {
172 const last = list.last ?? return null;
172 const last = list.last orelse return null;
173173 list.remove(last);
174174 return last;
175175 }
......@@ -179,7 +179,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
179179 /// Returns:
180180 /// A pointer to the first node in the list.
181181 pub fn popFirst(list: *Self) ?*Node {
182 const first = list.first ?? return null;
182 const first = list.first orelse return null;
183183 list.remove(first);
184184 return first;
185185 }
......@@ -270,8 +270,8 @@ test "basic linked list test" {
270270 var last = list.pop(); // {2, 3, 4}
271271 list.remove(three); // {2, 4}
272272
273 assert((??list.first).data == 2);
274 assert((??list.last).data == 4);
273 assert(list.first.?.data == 2);
274 assert(list.last.?.data == 4);
275275 assert(list.len == 2);
276276}
277277
......@@ -336,7 +336,7 @@ test "basic intrusive linked list test" {
336336 var last = list.pop(); // {2, 3, 4}
337337 list.remove(&three.link); // {2, 4}
338338
339 assert((??list.first).toData().value == 2);
340 assert((??list.last).toData().value == 4);
339 assert(list.first.?.toData().value == 2);
340 assert(list.last.?.toData().value == 4);
341341 assert(list.len == 2);
342342}
std/macho.zig+1-1
......@@ -130,7 +130,7 @@ pub fn loadSymbols(allocator: *mem.Allocator, in: *io.FileInStream) !SymbolTable
130130 for (syms) |sym| {
131131 if (!isSymbol(sym)) continue;
132132 const start = sym.n_strx;
133 const end = ??mem.indexOfScalarPos(u8, strings, start, 0);
133 const end = mem.indexOfScalarPos(u8, strings, start, 0).?;
134134 const name = strings[start..end];
135135 const address = sym.n_value;
136136 symbols[nsym] = Symbol{ .name = name, .address = address };
std/math/big/index.zig created+5
......@@ -0,0 +1,5 @@
1pub use @import("int.zig");
2
3test "math.big" {
4 _ = @import("int.zig");
5}
std/math/big/int.zig created+2023
......@@ -0,0 +1,2023 @@
1const std = @import("../../index.zig");
2const builtin = @import("builtin");
3const debug = std.debug;
4const math = std.math;
5const mem = std.mem;
6const Allocator = mem.Allocator;
7const ArrayList = std.ArrayList;
8
9const TypeId = builtin.TypeId;
10
11pub const Limb = usize;
12pub const DoubleLimb = @IntType(false, 2 * Limb.bit_count);
13pub const Log2Limb = math.Log2Int(Limb);
14
15comptime {
16 debug.assert(math.floorPowerOfTwo(usize, Limb.bit_count) == Limb.bit_count);
17 debug.assert(Limb.bit_count <= 64); // u128 set is unsupported
18 debug.assert(Limb.is_signed == false);
19}
20
21const wrapped_buffer_size = 512;
22
23// Converts primitive integer values onto a stack-based big integer, or passes through existing
24// Int types with no modifications. This can fail at runtime if using a very large dynamic
25// integer but it is very unlikely and is considered a user error.
26fn wrapInt(allocator: *Allocator, bn: var) *const Int {
27 const T = @typeOf(bn);
28 switch (@typeInfo(T)) {
29 TypeId.Pointer => |info| {
30 if (info.child == Int) {
31 return bn;
32 } else {
33 @compileError("cannot set Int using type " ++ @typeName(T));
34 }
35 },
36 else => {
37 var s = allocator.create(Int) catch unreachable;
38 s.* = Int{
39 .allocator = allocator,
40 .positive = false,
41 .limbs = block: {
42 var limbs = allocator.alloc(Limb, Int.default_capacity) catch unreachable;
43 limbs[0] = 0;
44 break :block limbs;
45 },
46 .len = 1,
47 };
48 s.set(bn) catch unreachable;
49 return s;
50 },
51 }
52}
53
54pub const Int = struct {
55 allocator: *Allocator,
56 positive: bool,
57 // - little-endian ordered
58 // - len >= 1 always
59 // - zero value -> len == 1 with limbs[0] == 0
60 limbs: []Limb,
61 len: usize,
62
63 const default_capacity = 4;
64
65 pub fn init(allocator: *Allocator) !Int {
66 return try Int.initCapacity(allocator, default_capacity);
67 }
68
69 pub fn initSet(allocator: *Allocator, value: var) !Int {
70 var s = try Int.init(allocator);
71 try s.set(value);
72 return s;
73 }
74
75 pub fn initCapacity(allocator: *Allocator, capacity: usize) !Int {
76 return Int{
77 .allocator = allocator,
78 .positive = true,
79 .limbs = block: {
80 var limbs = try allocator.alloc(Limb, math.max(default_capacity, capacity));
81 limbs[0] = 0;
82 break :block limbs;
83 },
84 .len = 1,
85 };
86 }
87
88 pub fn ensureCapacity(self: *Int, capacity: usize) !void {
89 if (capacity <= self.limbs.len) {
90 return;
91 }
92
93 self.limbs = try self.allocator.realloc(Limb, self.limbs, capacity);
94 }
95
96 pub fn deinit(self: *const Int) void {
97 self.allocator.free(self.limbs);
98 }
99
100 pub fn clone(other: *const Int) !Int {
101 return Int{
102 .allocator = other.allocator,
103 .positive = other.positive,
104 .limbs = block: {
105 var limbs = try other.allocator.alloc(Limb, other.len);
106 mem.copy(Limb, limbs[0..], other.limbs[0..other.len]);
107 break :block limbs;
108 },
109 .len = other.len,
110 };
111 }
112
113 pub fn copy(self: *Int, other: *const Int) !void {
114 if (self == other) {
115 return;
116 }
117
118 self.positive = other.positive;
119 try self.ensureCapacity(other.len);
120 mem.copy(Limb, self.limbs[0..], other.limbs[0..other.len]);
121 self.len = other.len;
122 }
123
124 pub fn swap(self: *Int, other: *Int) void {
125 mem.swap(Int, self, other);
126 }
127
128 pub fn dump(self: *const Int) void {
129 for (self.limbs) |limb| {
130 debug.warn("{x} ", limb);
131 }
132 debug.warn("\n");
133 }
134
135 pub fn negate(r: *Int) void {
136 r.positive = !r.positive;
137 }
138
139 pub fn abs(r: *Int) void {
140 r.positive = true;
141 }
142
143 pub fn isOdd(r: *const Int) bool {
144 return r.limbs[0] & 1 != 0;
145 }
146
147 pub fn isEven(r: *const Int) bool {
148 return !r.isOdd();
149 }
150
151 fn bitcount(self: *const Int) usize {
152 const u_bit_count = (self.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(self.limbs[self.len - 1]));
153 return usize(!self.positive) + u_bit_count;
154 }
155
156 pub fn sizeInBase(self: *const Int, base: usize) usize {
157 return (self.bitcount() / math.log2(base)) + 1;
158 }
159
160 pub fn set(self: *Int, value: var) Allocator.Error!void {
161 const T = @typeOf(value);
162
163 switch (@typeInfo(T)) {
164 TypeId.Int => |info| {
165 const UT = if (T.is_signed) @IntType(false, T.bit_count - 1) else T;
166
167 try self.ensureCapacity(@sizeOf(UT) / @sizeOf(Limb));
168 self.positive = value >= 0;
169 self.len = 0;
170
171 var w_value: UT = if (value < 0) UT(-value) else UT(value);
172
173 if (info.bits <= Limb.bit_count) {
174 self.limbs[0] = Limb(w_value);
175 self.len = 1;
176 } else {
177 var i: usize = 0;
178 while (w_value != 0) : (i += 1) {
179 self.limbs[i] = @truncate(Limb, w_value);
180 self.len += 1;
181
182 // TODO: shift == 64 at compile-time fails. Fails on u128 limbs.
183 w_value >>= Limb.bit_count / 2;
184 w_value >>= Limb.bit_count / 2;
185 }
186 }
187 },
188 TypeId.ComptimeInt => {
189 comptime var w_value = if (value < 0) -value else value;
190
191 const req_limbs = @divFloor(math.log2(w_value), Limb.bit_count) + 1;
192 try self.ensureCapacity(req_limbs);
193
194 self.positive = value >= 0;
195 self.len = req_limbs;
196
197 if (w_value <= @maxValue(Limb)) {
198 self.limbs[0] = w_value;
199 } else {
200 const mask = (1 << Limb.bit_count) - 1;
201
202 comptime var i = 0;
203 inline while (w_value != 0) : (i += 1) {
204 self.limbs[i] = w_value & mask;
205
206 w_value >>= Limb.bit_count / 2;
207 w_value >>= Limb.bit_count / 2;
208 }
209 }
210 },
211 else => {
212 @compileError("cannot set Int using type " ++ @typeName(T));
213 },
214 }
215 }
216
217 pub const ConvertError = error{
218 NegativeIntoUnsigned,
219 TargetTooSmall,
220 };
221
222 pub fn to(self: *const Int, comptime T: type) ConvertError!T {
223 switch (@typeId(T)) {
224 TypeId.Int => {
225 const UT = if (T.is_signed) @IntType(false, T.bit_count - 1) else T;
226
227 if (self.bitcount() > 8 * @sizeOf(UT)) {
228 return error.TargetTooSmall;
229 }
230
231 var r: UT = 0;
232
233 if (@sizeOf(UT) <= @sizeOf(Limb)) {
234 r = UT(self.limbs[0]);
235 } else {
236 for (self.limbs[0..self.len]) |_, ri| {
237 const limb = self.limbs[self.len - ri - 1];
238 r <<= Limb.bit_count;
239 r |= limb;
240 }
241 }
242
243 if (!T.is_signed) {
244 return if (self.positive) r else error.NegativeIntoUnsigned;
245 } else {
246 return if (self.positive) T(r) else -T(r);
247 }
248 },
249 else => {
250 @compileError("cannot convert Int to type " ++ @typeName(T));
251 },
252 }
253 }
254
255 fn charToDigit(ch: u8, base: u8) !u8 {
256 const d = switch (ch) {
257 '0'...'9' => ch - '0',
258 'a'...'f' => (ch - 'a') + 0xa,
259 else => return error.InvalidCharForDigit,
260 };
261
262 return if (d < base) d else return error.DigitTooLargeForBase;
263 }
264
265 fn digitToChar(d: u8, base: u8) !u8 {
266 if (d >= base) {
267 return error.DigitTooLargeForBase;
268 }
269
270 return switch (d) {
271 0...9 => '0' + d,
272 0xa...0xf => ('a' - 0xa) + d,
273 else => unreachable,
274 };
275 }
276
277 pub fn setString(self: *Int, base: u8, value: []const u8) !void {
278 if (base < 2 or base > 16) {
279 return error.InvalidBase;
280 }
281
282 var i: usize = 0;
283 var positive = true;
284 if (value.len > 0 and value[0] == '-') {
285 positive = false;
286 i += 1;
287 }
288
289 try self.set(0);
290 for (value[i..]) |ch| {
291 const d = try charToDigit(ch, base);
292 try self.mul(self, base);
293 try self.add(self, d);
294 }
295 self.positive = positive;
296 }
297
298 pub fn toString(self: *const Int, allocator: *Allocator, base: u8) ![]const u8 {
299 if (base < 2 or base > 16) {
300 return error.InvalidBase;
301 }
302
303 var digits = ArrayList(u8).init(allocator);
304 try digits.ensureCapacity(self.sizeInBase(base) + 1);
305 defer digits.deinit();
306
307 if (self.eqZero()) {
308 try digits.append('0');
309 return digits.toOwnedSlice();
310 }
311
312 // Power of two: can do a single pass and use masks to extract digits.
313 if (base & (base - 1) == 0) {
314 const base_shift = math.log2_int(Limb, base);
315
316 for (self.limbs[0..self.len]) |limb| {
317 var shift: usize = 0;
318 while (shift < Limb.bit_count) : (shift += base_shift) {
319 const r = u8((limb >> Log2Limb(shift)) & Limb(base - 1));
320 const ch = try digitToChar(r, base);
321 try digits.append(ch);
322 }
323 }
324
325 while (true) {
326 // always will have a non-zero digit somewhere
327 const c = digits.pop();
328 if (c != '0') {
329 digits.append(c) catch unreachable;
330 break;
331 }
332 }
333 } // Non power-of-two: batch divisions per word size.
334 else {
335 const digits_per_limb = math.log(Limb, base, @maxValue(Limb));
336 var limb_base: Limb = 1;
337 var j: usize = 0;
338 while (j < digits_per_limb) : (j += 1) {
339 limb_base *= base;
340 }
341
342 var q = try self.clone();
343 q.positive = true;
344 var r = try Int.init(allocator);
345 var b = try Int.initSet(allocator, limb_base);
346
347 while (q.len >= 2) {
348 try Int.divTrunc(&q, &r, &q, &b);
349
350 var r_word = r.limbs[0];
351 var i: usize = 0;
352 while (i < digits_per_limb) : (i += 1) {
353 const ch = try digitToChar(u8(r_word % base), base);
354 r_word /= base;
355 try digits.append(ch);
356 }
357 }
358
359 {
360 debug.assert(q.len == 1);
361
362 var r_word = q.limbs[0];
363 while (r_word != 0) {
364 const ch = try digitToChar(u8(r_word % base), base);
365 r_word /= base;
366 try digits.append(ch);
367 }
368 }
369 }
370
371 if (!self.positive) {
372 try digits.append('-');
373 }
374
375 var s = digits.toOwnedSlice();
376 mem.reverse(u8, s);
377 return s;
378 }
379
380 // returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.
381 pub fn cmpAbs(a: *const Int, bv: var) i8 {
382 // TODO: Thread-local buffer.
383 var buffer: [wrapped_buffer_size]u8 = undefined;
384 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
385 var b = wrapInt(&stack.allocator, bv);
386
387 if (a.len < b.len) {
388 return -1;
389 }
390 if (a.len > b.len) {
391 return 1;
392 }
393
394 var i: usize = a.len - 1;
395 while (i != 0) : (i -= 1) {
396 if (a.limbs[i] != b.limbs[i]) {
397 break;
398 }
399 }
400
401 if (a.limbs[i] < b.limbs[i]) {
402 return -1;
403 } else if (a.limbs[i] > b.limbs[i]) {
404 return 1;
405 } else {
406 return 0;
407 }
408 }
409
410 // returns -1, 0, 1 if a < b, a == b or a > b respectively.
411 pub fn cmp(a: *const Int, bv: var) i8 {
412 var buffer: [wrapped_buffer_size]u8 = undefined;
413 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
414 var b = wrapInt(&stack.allocator, bv);
415
416 if (a.positive != b.positive) {
417 return if (a.positive) i8(1) else -1;
418 } else {
419 const r = cmpAbs(a, b);
420 return if (a.positive) r else -r;
421 }
422 }
423
424 // if a == 0
425 pub fn eqZero(a: *const Int) bool {
426 return a.len == 1 and a.limbs[0] == 0;
427 }
428
429 // if |a| == |b|
430 pub fn eqAbs(a: *const Int, b: var) bool {
431 return cmpAbs(a, b) == 0;
432 }
433
434 // if a == b
435 pub fn eq(a: *const Int, b: var) bool {
436 return cmp(a, b) == 0;
437 }
438
439 // Normalize for a possible single carry digit.
440 //
441 // [1, 2, 3, 4, 0] -> [1, 2, 3, 4]
442 // [1, 2, 3, 4, 5] -> [1, 2, 3, 4, 5]
443 // [0] -> [0]
444 fn norm1(r: *Int, length: usize) void {
445 debug.assert(length > 0);
446 debug.assert(length <= r.limbs.len);
447
448 if (r.limbs[length - 1] == 0) {
449 r.len = if (length > 1) length - 1 else 1;
450 } else {
451 r.len = length;
452 }
453 }
454
455 // Normalize a possible sequence of leading zeros.
456 //
457 // [1, 2, 3, 4, 0] -> [1, 2, 3, 4]
458 // [1, 2, 0, 0, 0] -> [1, 2]
459 // [0, 0, 0, 0, 0] -> [0]
460 fn normN(r: *Int, length: usize) void {
461 debug.assert(length > 0);
462 debug.assert(length <= r.limbs.len);
463
464 var j = length;
465 while (j > 0) : (j -= 1) {
466 if (r.limbs[j - 1] != 0) {
467 break;
468 }
469 }
470
471 // Handle zero
472 r.len = if (j != 0) j else 1;
473 }
474
475 // r = a + b
476 pub fn add(r: *Int, av: var, bv: var) Allocator.Error!void {
477 var buffer: [2 * wrapped_buffer_size]u8 = undefined;
478 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
479 var a = wrapInt(&stack.allocator, av);
480 var b = wrapInt(&stack.allocator, bv);
481
482 if (a.eqZero()) {
483 try r.copy(b);
484 return;
485 } else if (b.eqZero()) {
486 try r.copy(a);
487 return;
488 }
489
490 if (a.positive != b.positive) {
491 if (a.positive) {
492 // (a) + (-b) => a - b
493 const bp = Int{
494 .allocator = undefined,
495 .positive = true,
496 .limbs = b.limbs,
497 .len = b.len,
498 };
499 try r.sub(a, bp);
500 } else {
501 // (-a) + (b) => b - a
502 const ap = Int{
503 .allocator = undefined,
504 .positive = true,
505 .limbs = a.limbs,
506 .len = a.len,
507 };
508 try r.sub(b, ap);
509 }
510 } else {
511 if (a.len >= b.len) {
512 try r.ensureCapacity(a.len + 1);
513 lladd(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
514 r.norm1(a.len + 1);
515 } else {
516 try r.ensureCapacity(b.len + 1);
517 lladd(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
518 r.norm1(b.len + 1);
519 }
520
521 r.positive = a.positive;
522 }
523 }
524
525 // Knuth 4.3.1, Algorithm A.
526 fn lladd(r: []Limb, a: []const Limb, b: []const Limb) void {
527 @setRuntimeSafety(false);
528 debug.assert(a.len != 0 and b.len != 0);
529 debug.assert(a.len >= b.len);
530 debug.assert(r.len >= a.len + 1);
531
532 var i: usize = 0;
533 var carry: Limb = 0;
534
535 while (i < b.len) : (i += 1) {
536 var c: Limb = 0;
537 c += Limb(@addWithOverflow(Limb, a[i], b[i], &r[i]));
538 c += Limb(@addWithOverflow(Limb, r[i], carry, &r[i]));
539 carry = c;
540 }
541
542 while (i < a.len) : (i += 1) {
543 carry = Limb(@addWithOverflow(Limb, a[i], carry, &r[i]));
544 }
545
546 r[i] = carry;
547 }
548
549 // r = a - b
550 pub fn sub(r: *Int, av: var, bv: var) !void {
551 var buffer: [wrapped_buffer_size]u8 = undefined;
552 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
553 var a = wrapInt(&stack.allocator, av);
554 var b = wrapInt(&stack.allocator, bv);
555
556 if (a.positive != b.positive) {
557 if (a.positive) {
558 // (a) - (-b) => a + b
559 const bp = Int{
560 .allocator = undefined,
561 .positive = true,
562 .limbs = b.limbs,
563 .len = b.len,
564 };
565 try r.add(a, bp);
566 } else {
567 // (-a) - (b) => -(a + b)
568 const ap = Int{
569 .allocator = undefined,
570 .positive = true,
571 .limbs = a.limbs,
572 .len = a.len,
573 };
574 try r.add(ap, b);
575 r.positive = false;
576 }
577 } else {
578 if (a.positive) {
579 // (a) - (b) => a - b
580 if (a.cmp(b) >= 0) {
581 try r.ensureCapacity(a.len + 1);
582 llsub(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
583 r.normN(a.len);
584 r.positive = true;
585 } else {
586 try r.ensureCapacity(b.len + 1);
587 llsub(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
588 r.normN(b.len);
589 r.positive = false;
590 }
591 } else {
592 // (-a) - (-b) => -(a - b)
593 if (a.cmp(b) < 0) {
594 try r.ensureCapacity(a.len + 1);
595 llsub(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
596 r.normN(a.len);
597 r.positive = false;
598 } else {
599 try r.ensureCapacity(b.len + 1);
600 llsub(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
601 r.normN(b.len);
602 r.positive = true;
603 }
604 }
605 }
606 }
607
608 // Knuth 4.3.1, Algorithm S.
609 fn llsub(r: []Limb, a: []const Limb, b: []const Limb) void {
610 @setRuntimeSafety(false);
611 debug.assert(a.len != 0 and b.len != 0);
612 debug.assert(a.len > b.len or (a.len == b.len and a[a.len - 1] >= b[b.len - 1]));
613 debug.assert(r.len >= a.len);
614
615 var i: usize = 0;
616 var borrow: Limb = 0;
617
618 while (i < b.len) : (i += 1) {
619 var c: Limb = 0;
620 c += Limb(@subWithOverflow(Limb, a[i], b[i], &r[i]));
621 c += Limb(@subWithOverflow(Limb, r[i], borrow, &r[i]));
622 borrow = c;
623 }
624
625 while (i < a.len) : (i += 1) {
626 borrow = Limb(@subWithOverflow(Limb, a[i], borrow, &r[i]));
627 }
628
629 debug.assert(borrow == 0);
630 }
631
632 // rma = a * b
633 //
634 // For greatest efficiency, ensure rma does not alias a or b.
635 pub fn mul(rma: *Int, av: var, bv: var) !void {
636 var buffer: [2 * wrapped_buffer_size]u8 = undefined;
637 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
638 var a = wrapInt(&stack.allocator, av);
639 var b = wrapInt(&stack.allocator, bv);
640
641 var r = rma;
642 var aliased = rma == a or rma == b;
643
644 var sr: Int = undefined;
645 if (aliased) {
646 sr = try Int.initCapacity(rma.allocator, a.len + b.len);
647 r = &sr;
648 aliased = true;
649 }
650 defer if (aliased) {
651 rma.swap(r);
652 r.deinit();
653 };
654
655 try r.ensureCapacity(a.len + b.len);
656
657 if (a.len >= b.len) {
658 llmul(r.limbs, a.limbs[0..a.len], b.limbs[0..b.len]);
659 } else {
660 llmul(r.limbs, b.limbs[0..b.len], a.limbs[0..a.len]);
661 }
662
663 r.positive = a.positive == b.positive;
664 r.normN(a.len + b.len);
665 }
666
667 // a + b * c + *carry, sets carry to the overflow bits
668 pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {
669 var r1: Limb = undefined;
670
671 // r1 = a + *carry
672 const c1 = Limb(@addWithOverflow(Limb, a, carry.*, &r1));
673
674 // r2 = b * c
675 //
676 // We still use a DoubleLimb here since the @mulWithOverflow builtin does not
677 // return the carry and lower bits separately so we would need to perform this
678 // anyway to get the carry bits. The branch on the overflow case costs more than
679 // just computing them unconditionally and splitting.
680 //
681 // This could be a single x86 mul instruction, which stores the carry/lower in rdx:rax.
682 const bc = DoubleLimb(b) * DoubleLimb(c);
683 const r2 = @truncate(Limb, bc);
684 const c2 = @truncate(Limb, bc >> Limb.bit_count);
685
686 // r1 = r1 + r2
687 const c3 = Limb(@addWithOverflow(Limb, r1, r2, &r1));
688
689 // This never overflows, c1, c3 are either 0 or 1 and if both are 1 then
690 // c2 is at least <= @maxValue(Limb) - 2.
691 carry.* = c1 + c2 + c3;
692
693 return r1;
694 }
695
696 // Knuth 4.3.1, Algorithm M.
697 //
698 // r MUST NOT alias any of a or b.
699 fn llmul(r: []Limb, a: []const Limb, b: []const Limb) void {
700 @setRuntimeSafety(false);
701 debug.assert(a.len >= b.len);
702 debug.assert(r.len >= a.len + b.len);
703
704 mem.set(Limb, r[0 .. a.len + b.len], 0);
705
706 var i: usize = 0;
707 while (i < a.len) : (i += 1) {
708 var carry: Limb = 0;
709 var j: usize = 0;
710 while (j < b.len) : (j += 1) {
711 r[i + j] = @inlineCall(addMulLimbWithCarry, r[i + j], a[i], b[j], &carry);
712 }
713 r[i + j] = carry;
714 }
715 }
716
717 pub fn divFloor(q: *Int, r: *Int, a: var, b: var) !void {
718 try div(q, r, a, b);
719
720 // Trunc -> Floor.
721 if (!q.positive) {
722 try q.sub(q, 1);
723 try r.add(q, 1);
724 }
725 r.positive = b.positive;
726 }
727
728 pub fn divTrunc(q: *Int, r: *Int, a: var, b: var) !void {
729 try div(q, r, a, b);
730 r.positive = a.positive;
731 }
732
733 // Truncates by default.
734 fn div(quo: *Int, rem: *Int, av: var, bv: var) !void {
735 var buffer: [2 * wrapped_buffer_size]u8 = undefined;
736 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
737 var a = wrapInt(&stack.allocator, av);
738 var b = wrapInt(&stack.allocator, bv);
739
740 if (b.eqZero()) {
741 @panic("division by zero");
742 }
743 if (quo == rem) {
744 @panic("quo and rem cannot be same variable");
745 }
746
747 if (a.cmpAbs(b) < 0) {
748 // quo may alias a so handle rem first
749 try rem.copy(a);
750 rem.positive = a.positive == b.positive;
751
752 quo.positive = true;
753 quo.len = 1;
754 quo.limbs[0] = 0;
755 return;
756 }
757
758 if (b.len == 1) {
759 try quo.ensureCapacity(a.len);
760
761 lldiv1(quo.limbs[0..], &rem.limbs[0], a.limbs[0..a.len], b.limbs[0]);
762 quo.norm1(a.len);
763 quo.positive = a.positive == b.positive;
764
765 rem.len = 1;
766 rem.positive = true;
767 } else {
768 // x and y are modified during division
769 var x = try a.clone();
770 defer x.deinit();
771
772 var y = try b.clone();
773 defer y.deinit();
774
775 // x may grow one limb during normalization
776 try quo.ensureCapacity(a.len + y.len);
777 try divN(quo.allocator, quo, rem, &x, &y);
778
779 quo.positive = a.positive == b.positive;
780 }
781 }
782
783 // Knuth 4.3.1, Exercise 16.
784 fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void {
785 @setRuntimeSafety(false);
786 debug.assert(a.len > 1 or a[0] >= b);
787 debug.assert(quo.len >= a.len);
788
789 rem.* = 0;
790 for (a) |_, ri| {
791 const i = a.len - ri - 1;
792 const pdiv = ((DoubleLimb(rem.*) << Limb.bit_count) | a[i]);
793
794 if (pdiv == 0) {
795 quo[i] = 0;
796 rem.* = 0;
797 } else if (pdiv < b) {
798 quo[i] = 0;
799 rem.* = @truncate(Limb, pdiv);
800 } else if (pdiv == b) {
801 quo[i] = 1;
802 rem.* = 0;
803 } else {
804 quo[i] = @truncate(Limb, @divTrunc(pdiv, b));
805 rem.* = @truncate(Limb, pdiv - (quo[i] *% b));
806 }
807 }
808 }
809
810 // Handbook of Applied Cryptography, 14.20
811 //
812 // x = qy + r where 0 <= r < y
813 fn divN(allocator: *Allocator, q: *Int, r: *Int, x: *Int, y: *Int) !void {
814 debug.assert(y.len >= 2);
815 debug.assert(x.len >= y.len);
816 debug.assert(q.limbs.len >= x.len + y.len - 1);
817 debug.assert(default_capacity >= 3); // see 3.2
818
819 var tmp = try Int.init(allocator);
820 defer tmp.deinit();
821
822 // Normalize so y > Limb.bit_count / 2 (i.e. leading bit is set)
823 const norm_shift = @clz(y.limbs[y.len - 1]);
824 try x.shiftLeft(x, norm_shift);
825 try y.shiftLeft(y, norm_shift);
826
827 const n = x.len - 1;
828 const t = y.len - 1;
829
830 // 1.
831 q.len = n - t + 1;
832 mem.set(Limb, q.limbs[0..q.len], 0);
833
834 // 2.
835 try tmp.shiftLeft(y, Limb.bit_count * (n - t));
836 while (x.cmp(&tmp) >= 0) {
837 q.limbs[n - t] += 1;
838 try x.sub(x, tmp);
839 }
840
841 // 3.
842 var i = n;
843 while (i > t) : (i -= 1) {
844 // 3.1
845 if (x.limbs[i] == y.limbs[t]) {
846 q.limbs[i - t - 1] = @maxValue(Limb);
847 } else {
848 const num = (DoubleLimb(x.limbs[i]) << Limb.bit_count) | DoubleLimb(x.limbs[i - 1]);
849 const z = Limb(num / DoubleLimb(y.limbs[t]));
850 q.limbs[i - t - 1] = if (z > @maxValue(Limb)) @maxValue(Limb) else Limb(z);
851 }
852
853 // 3.2
854 tmp.limbs[0] = if (i >= 2) x.limbs[i - 2] else 0;
855 tmp.limbs[1] = if (i >= 1) x.limbs[i - 1] else 0;
856 tmp.limbs[2] = x.limbs[i];
857 tmp.normN(3);
858
859 while (true) {
860 // 2x1 limb multiplication unrolled against single-limb q[i-t-1]
861 var carry: Limb = 0;
862 r.limbs[0] = addMulLimbWithCarry(0, if (t >= 1) y.limbs[t - 1] else 0, q.limbs[i - t - 1], &carry);
863 r.limbs[1] = addMulLimbWithCarry(0, y.limbs[t], q.limbs[i - t - 1], &carry);
864 r.limbs[2] = carry;
865 r.normN(3);
866
867 if (r.cmpAbs(&tmp) <= 0) {
868 break;
869 }
870
871 q.limbs[i - t - 1] -= 1;
872 }
873
874 // 3.3
875 try tmp.set(q.limbs[i - t - 1]);
876 try tmp.mul(&tmp, y);
877 try tmp.shiftLeft(&tmp, Limb.bit_count * (i - t - 1));
878 try x.sub(x, &tmp);
879
880 if (!x.positive) {
881 try tmp.shiftLeft(y, Limb.bit_count * (i - t - 1));
882 try x.add(x, &tmp);
883 q.limbs[i - t - 1] -= 1;
884 }
885 }
886
887 // Denormalize
888 q.normN(q.len);
889
890 try r.shiftRight(x, norm_shift);
891 r.normN(r.len);
892 }
893
894 // r = a << shift, in other words, r = a * 2^shift
895 pub fn shiftLeft(r: *Int, av: var, shift: usize) !void {
896 var buffer: [wrapped_buffer_size]u8 = undefined;
897 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
898 var a = wrapInt(&stack.allocator, av);
899
900 try r.ensureCapacity(a.len + (shift / Limb.bit_count) + 1);
901 llshl(r.limbs[0..], a.limbs[0..a.len], shift);
902 r.norm1(a.len + (shift / Limb.bit_count) + 1);
903 r.positive = a.positive;
904 }
905
906 fn llshl(r: []Limb, a: []const Limb, shift: usize) void {
907 @setRuntimeSafety(false);
908 debug.assert(a.len >= 1);
909 debug.assert(r.len >= a.len + (shift / Limb.bit_count) + 1);
910
911 const limb_shift = shift / Limb.bit_count + 1;
912 const interior_limb_shift = Log2Limb(shift % Limb.bit_count);
913
914 var carry: Limb = 0;
915 var i: usize = 0;
916 while (i < a.len) : (i += 1) {
917 const src_i = a.len - i - 1;
918 const dst_i = src_i + limb_shift;
919
920 const src_digit = a[src_i];
921 r[dst_i] = carry | @inlineCall(math.shr, Limb, src_digit, Limb.bit_count - Limb(interior_limb_shift));
922 carry = (src_digit << interior_limb_shift);
923 }
924
925 r[limb_shift - 1] = carry;
926 mem.set(Limb, r[0 .. limb_shift - 1], 0);
927 }
928
929 // r = a >> shift
930 pub fn shiftRight(r: *Int, av: var, shift: usize) !void {
931 var buffer: [wrapped_buffer_size]u8 = undefined;
932 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
933 var a = wrapInt(&stack.allocator, av);
934
935 if (a.len <= shift / Limb.bit_count) {
936 r.len = 1;
937 r.limbs[0] = 0;
938 r.positive = true;
939 return;
940 }
941
942 try r.ensureCapacity(a.len - (shift / Limb.bit_count));
943 const r_len = llshr(r.limbs[0..], a.limbs[0..a.len], shift);
944 r.len = a.len - (shift / Limb.bit_count);
945 r.positive = a.positive;
946 }
947
948 fn llshr(r: []Limb, a: []const Limb, shift: usize) void {
949 @setRuntimeSafety(false);
950 debug.assert(a.len >= 1);
951 debug.assert(r.len >= a.len - (shift / Limb.bit_count));
952
953 const limb_shift = shift / Limb.bit_count;
954 const interior_limb_shift = Log2Limb(shift % Limb.bit_count);
955
956 var carry: Limb = 0;
957 var i: usize = 0;
958 while (i < a.len - limb_shift) : (i += 1) {
959 const src_i = a.len - i - 1;
960 const dst_i = src_i - limb_shift;
961
962 const src_digit = a[src_i];
963 r[dst_i] = carry | (src_digit >> interior_limb_shift);
964 carry = @inlineCall(math.shl, Limb, src_digit, Limb.bit_count - Limb(interior_limb_shift));
965 }
966 }
967
968 // r = a | b
969 pub fn bitOr(r: *Int, av: var, bv: var) !void {
970 var buffer: [2 * wrapped_buffer_size]u8 = undefined;
971 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
972 var a = wrapInt(&stack.allocator, av);
973 var b = wrapInt(&stack.allocator, bv);
974
975 if (a.len > b.len) {
976 try r.ensureCapacity(a.len);
977 llor(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
978 r.len = a.len;
979 } else {
980 try r.ensureCapacity(b.len);
981 llor(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
982 r.len = b.len;
983 }
984 }
985
986 fn llor(r: []Limb, a: []const Limb, b: []const Limb) void {
987 @setRuntimeSafety(false);
988 debug.assert(r.len >= a.len);
989 debug.assert(a.len >= b.len);
990
991 var i: usize = 0;
992 while (i < b.len) : (i += 1) {
993 r[i] = a[i] | b[i];
994 }
995 while (i < a.len) : (i += 1) {
996 r[i] = a[i];
997 }
998 }
999
1000 // r = a & b
1001 pub fn bitAnd(r: *Int, av: var, bv: var) !void {
1002 var buffer: [2 * wrapped_buffer_size]u8 = undefined;
1003 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
1004 var a = wrapInt(&stack.allocator, av);
1005 var b = wrapInt(&stack.allocator, bv);
1006
1007 if (a.len > b.len) {
1008 try r.ensureCapacity(b.len);
1009 lland(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
1010 r.normN(b.len);
1011 } else {
1012 try r.ensureCapacity(a.len);
1013 lland(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
1014 r.normN(a.len);
1015 }
1016 }
1017
1018 fn lland(r: []Limb, a: []const Limb, b: []const Limb) void {
1019 @setRuntimeSafety(false);
1020 debug.assert(r.len >= b.len);
1021 debug.assert(a.len >= b.len);
1022
1023 var i: usize = 0;
1024 while (i < b.len) : (i += 1) {
1025 r[i] = a[i] & b[i];
1026 }
1027 }
1028
1029 // r = a ^ b
1030 pub fn bitXor(r: *Int, av: var, bv: var) !void {
1031 var buffer: [2 * wrapped_buffer_size]u8 = undefined;
1032 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
1033 var a = wrapInt(&stack.allocator, av);
1034 var b = wrapInt(&stack.allocator, bv);
1035
1036 if (a.len > b.len) {
1037 try r.ensureCapacity(a.len);
1038 llxor(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
1039 r.normN(a.len);
1040 } else {
1041 try r.ensureCapacity(b.len);
1042 llxor(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
1043 r.normN(b.len);
1044 }
1045 }
1046
1047 fn llxor(r: []Limb, a: []const Limb, b: []const Limb) void {
1048 @setRuntimeSafety(false);
1049 debug.assert(r.len >= a.len);
1050 debug.assert(a.len >= b.len);
1051
1052 var i: usize = 0;
1053 while (i < b.len) : (i += 1) {
1054 r[i] = a[i] ^ b[i];
1055 }
1056 while (i < a.len) : (i += 1) {
1057 r[i] = a[i];
1058 }
1059 }
1060};
1061
1062// NOTE: All the following tests assume the max machine-word will be 64-bit.
1063//
1064// They will still run on larger than this and should pass, but the multi-limb code-paths
1065// may be untested in some cases.
1066
1067const u256 = @IntType(false, 256);
1068var al = debug.global_allocator;
1069
1070test "big.int comptime_int set" {
1071 comptime var s = 0xefffffff00000001eeeeeeefaaaaaaab;
1072 var a = try Int.initSet(al, s);
1073
1074 const s_limb_count = 128 / Limb.bit_count;
1075
1076 comptime var i: usize = 0;
1077 inline while (i < s_limb_count) : (i += 1) {
1078 const result = Limb(s & @maxValue(Limb));
1079 s >>= Limb.bit_count / 2;
1080 s >>= Limb.bit_count / 2;
1081 debug.assert(a.limbs[i] == result);
1082 }
1083}
1084
1085test "big.int comptime_int set negative" {
1086 var a = try Int.initSet(al, -10);
1087
1088 debug.assert(a.limbs[0] == 10);
1089 debug.assert(a.positive == false);
1090}
1091
1092test "big.int int set unaligned small" {
1093 var a = try Int.initSet(al, u7(45));
1094
1095 debug.assert(a.limbs[0] == 45);
1096 debug.assert(a.positive == true);
1097}
1098
1099test "big.int comptime_int to" {
1100 const a = try Int.initSet(al, 0xefffffff00000001eeeeeeefaaaaaaab);
1101
1102 debug.assert((try a.to(u128)) == 0xefffffff00000001eeeeeeefaaaaaaab);
1103}
1104
1105test "big.int sub-limb to" {
1106 const a = try Int.initSet(al, 10);
1107
1108 debug.assert((try a.to(u8)) == 10);
1109}
1110
1111test "big.int to target too small error" {
1112 const a = try Int.initSet(al, 0xffffffff);
1113
1114 if (a.to(u8)) |_| {
1115 unreachable;
1116 } else |err| {
1117 debug.assert(err == error.TargetTooSmall);
1118 }
1119}
1120
1121test "big.int norm1" {
1122 var a = try Int.init(al);
1123 try a.ensureCapacity(8);
1124
1125 a.limbs[0] = 1;
1126 a.limbs[1] = 2;
1127 a.limbs[2] = 3;
1128 a.limbs[3] = 0;
1129 a.norm1(4);
1130 debug.assert(a.len == 3);
1131
1132 a.limbs[0] = 1;
1133 a.limbs[1] = 2;
1134 a.limbs[2] = 3;
1135 a.norm1(3);
1136 debug.assert(a.len == 3);
1137
1138 a.limbs[0] = 0;
1139 a.limbs[1] = 0;
1140 a.norm1(2);
1141 debug.assert(a.len == 1);
1142
1143 a.limbs[0] = 0;
1144 a.norm1(1);
1145 debug.assert(a.len == 1);
1146}
1147
1148test "big.int normN" {
1149 var a = try Int.init(al);
1150 try a.ensureCapacity(8);
1151
1152 a.limbs[0] = 1;
1153 a.limbs[1] = 2;
1154 a.limbs[2] = 0;
1155 a.limbs[3] = 0;
1156 a.normN(4);
1157 debug.assert(a.len == 2);
1158
1159 a.limbs[0] = 1;
1160 a.limbs[1] = 2;
1161 a.limbs[2] = 3;
1162 a.normN(3);
1163 debug.assert(a.len == 3);
1164
1165 a.limbs[0] = 0;
1166 a.limbs[1] = 0;
1167 a.limbs[2] = 0;
1168 a.limbs[3] = 0;
1169 a.normN(4);
1170 debug.assert(a.len == 1);
1171
1172 a.limbs[0] = 0;
1173 a.normN(1);
1174 debug.assert(a.len == 1);
1175}
1176
1177test "big.int parity" {
1178 var a = try Int.init(al);
1179 try a.set(0);
1180 debug.assert(a.isEven());
1181 debug.assert(!a.isOdd());
1182
1183 try a.set(7);
1184 debug.assert(!a.isEven());
1185 debug.assert(a.isOdd());
1186}
1187
1188test "big.int bitcount + sizeInBase" {
1189 var a = try Int.init(al);
1190
1191 try a.set(0b100);
1192 debug.assert(a.bitcount() == 3);
1193 debug.assert(a.sizeInBase(2) >= 3);
1194 debug.assert(a.sizeInBase(10) >= 1);
1195
1196 try a.set(0xffffffff);
1197 debug.assert(a.bitcount() == 32);
1198 debug.assert(a.sizeInBase(2) >= 32);
1199 debug.assert(a.sizeInBase(10) >= 10);
1200
1201 try a.shiftLeft(&a, 5000);
1202 debug.assert(a.bitcount() == 5032);
1203 debug.assert(a.sizeInBase(2) >= 5032);
1204 a.positive = false;
1205
1206 debug.assert(a.bitcount() == 5033);
1207 debug.assert(a.sizeInBase(2) >= 5033);
1208}
1209
1210test "big.int string set" {
1211 var a = try Int.init(al);
1212 try a.setString(10, "120317241209124781241290847124");
1213
1214 debug.assert((try a.to(u128)) == 120317241209124781241290847124);
1215}
1216
1217test "big.int string negative" {
1218 var a = try Int.init(al);
1219 try a.setString(10, "-1023");
1220 debug.assert((try a.to(i32)) == -1023);
1221}
1222
1223test "big.int string set bad char error" {
1224 var a = try Int.init(al);
1225 a.setString(10, "x") catch |err| debug.assert(err == error.InvalidCharForDigit);
1226}
1227
1228test "big.int string set bad base error" {
1229 var a = try Int.init(al);
1230 a.setString(45, "10") catch |err| debug.assert(err == error.InvalidBase);
1231}
1232
1233test "big.int string to" {
1234 const a = try Int.initSet(al, 120317241209124781241290847124);
1235
1236 const as = try a.toString(al, 10);
1237 const es = "120317241209124781241290847124";
1238
1239 debug.assert(mem.eql(u8, as, es));
1240}
1241
1242test "big.int string to base base error" {
1243 const a = try Int.initSet(al, 0xffffffff);
1244
1245 if (a.toString(al, 45)) |_| {
1246 unreachable;
1247 } else |err| {
1248 debug.assert(err == error.InvalidBase);
1249 }
1250}
1251
1252test "big.int string to base 2" {
1253 const a = try Int.initSet(al, -0b1011);
1254
1255 const as = try a.toString(al, 2);
1256 const es = "-1011";
1257
1258 debug.assert(mem.eql(u8, as, es));
1259}
1260
1261test "big.int string to base 16" {
1262 const a = try Int.initSet(al, 0xefffffff00000001eeeeeeefaaaaaaab);
1263
1264 const as = try a.toString(al, 16);
1265 const es = "efffffff00000001eeeeeeefaaaaaaab";
1266
1267 debug.assert(mem.eql(u8, as, es));
1268}
1269
1270test "big.int neg string to" {
1271 const a = try Int.initSet(al, -123907434);
1272
1273 const as = try a.toString(al, 10);
1274 const es = "-123907434";
1275
1276 debug.assert(mem.eql(u8, as, es));
1277}
1278
1279test "big.int zero string to" {
1280 const a = try Int.initSet(al, 0);
1281
1282 const as = try a.toString(al, 10);
1283 const es = "0";
1284
1285 debug.assert(mem.eql(u8, as, es));
1286}
1287
1288test "big.int clone" {
1289 var a = try Int.initSet(al, 1234);
1290 const b = try a.clone();
1291
1292 debug.assert((try a.to(u32)) == 1234);
1293 debug.assert((try b.to(u32)) == 1234);
1294
1295 try a.set(77);
1296 debug.assert((try a.to(u32)) == 77);
1297 debug.assert((try b.to(u32)) == 1234);
1298}
1299
1300test "big.int swap" {
1301 var a = try Int.initSet(al, 1234);
1302 var b = try Int.initSet(al, 5678);
1303
1304 debug.assert((try a.to(u32)) == 1234);
1305 debug.assert((try b.to(u32)) == 5678);
1306
1307 a.swap(&b);
1308
1309 debug.assert((try a.to(u32)) == 5678);
1310 debug.assert((try b.to(u32)) == 1234);
1311}
1312
1313test "big.int to negative" {
1314 var a = try Int.initSet(al, -10);
1315
1316 debug.assert((try a.to(i32)) == -10);
1317}
1318
1319test "big.int compare" {
1320 var a = try Int.initSet(al, -11);
1321 var b = try Int.initSet(al, 10);
1322
1323 debug.assert(a.cmpAbs(&b) == 1);
1324 debug.assert(a.cmp(&b) == -1);
1325}
1326
1327test "big.int compare similar" {
1328 var a = try Int.initSet(al, 0xffffffffeeeeeeeeffffffffeeeeeeee);
1329 var b = try Int.initSet(al, 0xffffffffeeeeeeeeffffffffeeeeeeef);
1330
1331 debug.assert(a.cmpAbs(&b) == -1);
1332 debug.assert(b.cmpAbs(&a) == 1);
1333}
1334
1335test "big.int compare different limb size" {
1336 var a = try Int.initSet(al, @maxValue(Limb) + 1);
1337 var b = try Int.initSet(al, 1);
1338
1339 debug.assert(a.cmpAbs(&b) == 1);
1340 debug.assert(b.cmpAbs(&a) == -1);
1341}
1342
1343test "big.int compare multi-limb" {
1344 var a = try Int.initSet(al, -0x7777777799999999ffffeeeeffffeeeeffffeeeef);
1345 var b = try Int.initSet(al, 0x7777777799999999ffffeeeeffffeeeeffffeeeee);
1346
1347 debug.assert(a.cmpAbs(&b) == 1);
1348 debug.assert(a.cmp(&b) == -1);
1349}
1350
1351test "big.int equality" {
1352 var a = try Int.initSet(al, 0xffffffff1);
1353 var b = try Int.initSet(al, -0xffffffff1);
1354
1355 debug.assert(a.eqAbs(&b));
1356 debug.assert(!a.eq(&b));
1357}
1358
1359test "big.int abs" {
1360 var a = try Int.initSet(al, -5);
1361
1362 a.abs();
1363 debug.assert((try a.to(u32)) == 5);
1364
1365 a.abs();
1366 debug.assert((try a.to(u32)) == 5);
1367}
1368
1369test "big.int negate" {
1370 var a = try Int.initSet(al, 5);
1371
1372 a.negate();
1373 debug.assert((try a.to(i32)) == -5);
1374
1375 a.negate();
1376 debug.assert((try a.to(i32)) == 5);
1377}
1378
1379test "big.int add single-single" {
1380 var a = try Int.initSet(al, 50);
1381 var b = try Int.initSet(al, 5);
1382
1383 var c = try Int.init(al);
1384 try c.add(&a, &b);
1385
1386 debug.assert((try c.to(u32)) == 55);
1387}
1388
1389test "big.int add multi-single" {
1390 var a = try Int.initSet(al, @maxValue(Limb) + 1);
1391 var b = try Int.initSet(al, 1);
1392
1393 var c = try Int.init(al);
1394
1395 try c.add(&a, &b);
1396 debug.assert((try c.to(DoubleLimb)) == @maxValue(Limb) + 2);
1397
1398 try c.add(&b, &a);
1399 debug.assert((try c.to(DoubleLimb)) == @maxValue(Limb) + 2);
1400}
1401
1402test "big.int add multi-multi" {
1403 const op1 = 0xefefefef7f7f7f7f;
1404 const op2 = 0xfefefefe9f9f9f9f;
1405 var a = try Int.initSet(al, op1);
1406 var b = try Int.initSet(al, op2);
1407
1408 var c = try Int.init(al);
1409 try c.add(&a, &b);
1410
1411 debug.assert((try c.to(u128)) == op1 + op2);
1412}
1413
1414test "big.int add zero-zero" {
1415 var a = try Int.initSet(al, 0);
1416 var b = try Int.initSet(al, 0);
1417
1418 var c = try Int.init(al);
1419 try c.add(&a, &b);
1420
1421 debug.assert((try c.to(u32)) == 0);
1422}
1423
1424test "big.int add alias multi-limb nonzero-zero" {
1425 const op1 = 0xffffffff777777771;
1426 var a = try Int.initSet(al, op1);
1427 var b = try Int.initSet(al, 0);
1428
1429 try a.add(&a, &b);
1430
1431 debug.assert((try a.to(u128)) == op1);
1432}
1433
1434test "big.int add sign" {
1435 var a = try Int.init(al);
1436
1437 try a.add(1, 2);
1438 debug.assert((try a.to(i32)) == 3);
1439
1440 try a.add(-1, 2);
1441 debug.assert((try a.to(i32)) == 1);
1442
1443 try a.add(1, -2);
1444 debug.assert((try a.to(i32)) == -1);
1445
1446 try a.add(-1, -2);
1447 debug.assert((try a.to(i32)) == -3);
1448}
1449
1450test "big.int sub single-single" {
1451 var a = try Int.initSet(al, 50);
1452 var b = try Int.initSet(al, 5);
1453
1454 var c = try Int.init(al);
1455 try c.sub(&a, &b);
1456
1457 debug.assert((try c.to(u32)) == 45);
1458}
1459
1460test "big.int sub multi-single" {
1461 var a = try Int.initSet(al, @maxValue(Limb) + 1);
1462 var b = try Int.initSet(al, 1);
1463
1464 var c = try Int.init(al);
1465 try c.sub(&a, &b);
1466
1467 debug.assert((try c.to(Limb)) == @maxValue(Limb));
1468}
1469
1470test "big.int sub multi-multi" {
1471 const op1 = 0xefefefefefefefefefefefef;
1472 const op2 = 0xabababababababababababab;
1473
1474 var a = try Int.initSet(al, op1);
1475 var b = try Int.initSet(al, op2);
1476
1477 var c = try Int.init(al);
1478 try c.sub(&a, &b);
1479
1480 debug.assert((try c.to(u128)) == op1 - op2);
1481}
1482
1483test "big.int sub equal" {
1484 var a = try Int.initSet(al, 0x11efefefefefefefefefefefef);
1485 var b = try Int.initSet(al, 0x11efefefefefefefefefefefef);
1486
1487 var c = try Int.init(al);
1488 try c.sub(&a, &b);
1489
1490 debug.assert((try c.to(u32)) == 0);
1491}
1492
1493test "big.int sub sign" {
1494 var a = try Int.init(al);
1495
1496 try a.sub(1, 2);
1497 debug.assert((try a.to(i32)) == -1);
1498
1499 try a.sub(-1, 2);
1500 debug.assert((try a.to(i32)) == -3);
1501
1502 try a.sub(1, -2);
1503 debug.assert((try a.to(i32)) == 3);
1504
1505 try a.sub(-1, -2);
1506 debug.assert((try a.to(i32)) == 1);
1507
1508 try a.sub(-2, -1);
1509 debug.assert((try a.to(i32)) == -1);
1510}
1511
1512test "big.int mul single-single" {
1513 var a = try Int.initSet(al, 50);
1514 var b = try Int.initSet(al, 5);
1515
1516 var c = try Int.init(al);
1517 try c.mul(&a, &b);
1518
1519 debug.assert((try c.to(u64)) == 250);
1520}
1521
1522test "big.int mul multi-single" {
1523 var a = try Int.initSet(al, @maxValue(Limb));
1524 var b = try Int.initSet(al, 2);
1525
1526 var c = try Int.init(al);
1527 try c.mul(&a, &b);
1528
1529 debug.assert((try c.to(DoubleLimb)) == 2 * @maxValue(Limb));
1530}
1531
1532test "big.int mul multi-multi" {
1533 const op1 = 0x998888efefefefefefefef;
1534 const op2 = 0x333000abababababababab;
1535 var a = try Int.initSet(al, op1);
1536 var b = try Int.initSet(al, op2);
1537
1538 var c = try Int.init(al);
1539 try c.mul(&a, &b);
1540
1541 debug.assert((try c.to(u256)) == op1 * op2);
1542}
1543
1544test "big.int mul alias r with a" {
1545 var a = try Int.initSet(al, @maxValue(Limb));
1546 var b = try Int.initSet(al, 2);
1547
1548 try a.mul(&a, &b);
1549
1550 debug.assert((try a.to(DoubleLimb)) == 2 * @maxValue(Limb));
1551}
1552
1553test "big.int mul alias r with b" {
1554 var a = try Int.initSet(al, @maxValue(Limb));
1555 var b = try Int.initSet(al, 2);
1556
1557 try a.mul(&b, &a);
1558
1559 debug.assert((try a.to(DoubleLimb)) == 2 * @maxValue(Limb));
1560}
1561
1562test "big.int mul alias r with a and b" {
1563 var a = try Int.initSet(al, @maxValue(Limb));
1564
1565 try a.mul(&a, &a);
1566
1567 debug.assert((try a.to(DoubleLimb)) == @maxValue(Limb) * @maxValue(Limb));
1568}
1569
1570test "big.int mul a*0" {
1571 var a = try Int.initSet(al, 0xefefefefefefefef);
1572 var b = try Int.initSet(al, 0);
1573
1574 var c = try Int.init(al);
1575 try c.mul(&a, &b);
1576
1577 debug.assert((try c.to(u32)) == 0);
1578}
1579
1580test "big.int mul 0*0" {
1581 var a = try Int.initSet(al, 0);
1582 var b = try Int.initSet(al, 0);
1583
1584 var c = try Int.init(al);
1585 try c.mul(&a, &b);
1586
1587 debug.assert((try c.to(u32)) == 0);
1588}
1589
1590test "big.int div single-single no rem" {
1591 var a = try Int.initSet(al, 50);
1592 var b = try Int.initSet(al, 5);
1593
1594 var q = try Int.init(al);
1595 var r = try Int.init(al);
1596 try Int.divTrunc(&q, &r, &a, &b);
1597
1598 debug.assert((try q.to(u32)) == 10);
1599 debug.assert((try r.to(u32)) == 0);
1600}
1601
1602test "big.int div single-single with rem" {
1603 var a = try Int.initSet(al, 49);
1604 var b = try Int.initSet(al, 5);
1605
1606 var q = try Int.init(al);
1607 var r = try Int.init(al);
1608 try Int.divTrunc(&q, &r, &a, &b);
1609
1610 debug.assert((try q.to(u32)) == 9);
1611 debug.assert((try r.to(u32)) == 4);
1612}
1613
1614test "big.int div multi-single no rem" {
1615 const op1 = 0xffffeeeeddddcccc;
1616 const op2 = 34;
1617
1618 var a = try Int.initSet(al, op1);
1619 var b = try Int.initSet(al, op2);
1620
1621 var q = try Int.init(al);
1622 var r = try Int.init(al);
1623 try Int.divTrunc(&q, &r, &a, &b);
1624
1625 debug.assert((try q.to(u64)) == op1 / op2);
1626 debug.assert((try r.to(u64)) == 0);
1627}
1628
1629test "big.int div multi-single with rem" {
1630 const op1 = 0xffffeeeeddddcccf;
1631 const op2 = 34;
1632
1633 var a = try Int.initSet(al, op1);
1634 var b = try Int.initSet(al, op2);
1635
1636 var q = try Int.init(al);
1637 var r = try Int.init(al);
1638 try Int.divTrunc(&q, &r, &a, &b);
1639
1640 debug.assert((try q.to(u64)) == op1 / op2);
1641 debug.assert((try r.to(u64)) == 3);
1642}
1643
1644test "big.int div multi>2-single" {
1645 const op1 = 0xfefefefefefefefefefefefefefefefe;
1646 const op2 = 0xefab8;
1647
1648 var a = try Int.initSet(al, op1);
1649 var b = try Int.initSet(al, op2);
1650
1651 var q = try Int.init(al);
1652 var r = try Int.init(al);
1653 try Int.divTrunc(&q, &r, &a, &b);
1654
1655 debug.assert((try q.to(u128)) == op1 / op2);
1656 debug.assert((try r.to(u32)) == 0x3e4e);
1657}
1658
1659test "big.int div single-single q < r" {
1660 var a = try Int.initSet(al, 0x0078f432);
1661 var b = try Int.initSet(al, 0x01000000);
1662
1663 var q = try Int.init(al);
1664 var r = try Int.init(al);
1665 try Int.divTrunc(&q, &r, &a, &b);
1666
1667 debug.assert((try q.to(u64)) == 0);
1668 debug.assert((try r.to(u64)) == 0x0078f432);
1669}
1670
1671test "big.int div single-single q == r" {
1672 var a = try Int.initSet(al, 10);
1673 var b = try Int.initSet(al, 10);
1674
1675 var q = try Int.init(al);
1676 var r = try Int.init(al);
1677 try Int.divTrunc(&q, &r, &a, &b);
1678
1679 debug.assert((try q.to(u64)) == 1);
1680 debug.assert((try r.to(u64)) == 0);
1681}
1682
1683test "big.int div q=0 alias" {
1684 var a = try Int.initSet(al, 3);
1685 var b = try Int.initSet(al, 10);
1686
1687 try Int.divTrunc(&a, &b, &a, &b);
1688
1689 debug.assert((try a.to(u64)) == 0);
1690 debug.assert((try b.to(u64)) == 3);
1691}
1692
1693test "big.int div multi-multi q < r" {
1694 const op1 = 0x1ffffffff0078f432;
1695 const op2 = 0x1ffffffff01000000;
1696 var a = try Int.initSet(al, op1);
1697 var b = try Int.initSet(al, op2);
1698
1699 var q = try Int.init(al);
1700 var r = try Int.init(al);
1701 try Int.divTrunc(&q, &r, &a, &b);
1702
1703 debug.assert((try q.to(u128)) == 0);
1704 debug.assert((try r.to(u128)) == op1);
1705}
1706
1707test "big.int div trunc single-single +/+" {
1708 const u: i32 = 5;
1709 const v: i32 = 3;
1710
1711 var a = try Int.initSet(al, u);
1712 var b = try Int.initSet(al, v);
1713
1714 var q = try Int.init(al);
1715 var r = try Int.init(al);
1716 try Int.divTrunc(&q, &r, &a, &b);
1717
1718 // n = q * d + r
1719 // 5 = 1 * 3 + 2
1720 const eq = @divTrunc(u, v);
1721 const er = @mod(u, v);
1722
1723 debug.assert((try q.to(i32)) == eq);
1724 debug.assert((try r.to(i32)) == er);
1725}
1726
1727test "big.int div trunc single-single -/+" {
1728 const u: i32 = -5;
1729 const v: i32 = 3;
1730
1731 var a = try Int.initSet(al, u);
1732 var b = try Int.initSet(al, v);
1733
1734 var q = try Int.init(al);
1735 var r = try Int.init(al);
1736 try Int.divTrunc(&q, &r, &a, &b);
1737
1738 // n = q * d + r
1739 // -5 = 1 * -3 - 2
1740 const eq = -1;
1741 const er = -2;
1742
1743 debug.assert((try q.to(i32)) == eq);
1744 debug.assert((try r.to(i32)) == er);
1745}
1746
1747test "big.int div trunc single-single +/-" {
1748 const u: i32 = 5;
1749 const v: i32 = -3;
1750
1751 var a = try Int.initSet(al, u);
1752 var b = try Int.initSet(al, v);
1753
1754 var q = try Int.init(al);
1755 var r = try Int.init(al);
1756 try Int.divTrunc(&q, &r, &a, &b);
1757
1758 // n = q * d + r
1759 // 5 = -1 * -3 + 2
1760 const eq = -1;
1761 const er = 2;
1762
1763 debug.assert((try q.to(i32)) == eq);
1764 debug.assert((try r.to(i32)) == er);
1765}
1766
1767test "big.int div trunc single-single -/-" {
1768 const u: i32 = -5;
1769 const v: i32 = -3;
1770
1771 var a = try Int.initSet(al, u);
1772 var b = try Int.initSet(al, v);
1773
1774 var q = try Int.init(al);
1775 var r = try Int.init(al);
1776 try Int.divTrunc(&q, &r, &a, &b);
1777
1778 // n = q * d + r
1779 // -5 = 1 * -3 - 2
1780 const eq = 1;
1781 const er = -2;
1782
1783 debug.assert((try q.to(i32)) == eq);
1784 debug.assert((try r.to(i32)) == er);
1785}
1786
1787test "big.int div floor single-single +/+" {
1788 const u: i32 = 5;
1789 const v: i32 = 3;
1790
1791 var a = try Int.initSet(al, u);
1792 var b = try Int.initSet(al, v);
1793
1794 var q = try Int.init(al);
1795 var r = try Int.init(al);
1796 try Int.divFloor(&q, &r, &a, &b);
1797
1798 // n = q * d + r
1799 // 5 = 1 * 3 + 2
1800 const eq = 1;
1801 const er = 2;
1802
1803 debug.assert((try q.to(i32)) == eq);
1804 debug.assert((try r.to(i32)) == er);
1805}
1806
1807test "big.int div floor single-single -/+" {
1808 const u: i32 = -5;
1809 const v: i32 = 3;
1810
1811 var a = try Int.initSet(al, u);
1812 var b = try Int.initSet(al, v);
1813
1814 var q = try Int.init(al);
1815 var r = try Int.init(al);
1816 try Int.divFloor(&q, &r, &a, &b);
1817
1818 // n = q * d + r
1819 // -5 = -2 * 3 + 1
1820 const eq = -2;
1821 const er = 1;
1822
1823 debug.assert((try q.to(i32)) == eq);
1824 debug.assert((try r.to(i32)) == er);
1825}
1826
1827test "big.int div floor single-single +/-" {
1828 const u: i32 = 5;
1829 const v: i32 = -3;
1830
1831 var a = try Int.initSet(al, u);
1832 var b = try Int.initSet(al, v);
1833
1834 var q = try Int.init(al);
1835 var r = try Int.init(al);
1836 try Int.divFloor(&q, &r, &a, &b);
1837
1838 // n = q * d + r
1839 // 5 = -2 * -3 - 1
1840 const eq = -2;
1841 const er = -1;
1842
1843 debug.assert((try q.to(i32)) == eq);
1844 debug.assert((try r.to(i32)) == er);
1845}
1846
1847test "big.int div floor single-single -/-" {
1848 const u: i32 = -5;
1849 const v: i32 = -3;
1850
1851 var a = try Int.initSet(al, u);
1852 var b = try Int.initSet(al, v);
1853
1854 var q = try Int.init(al);
1855 var r = try Int.init(al);
1856 try Int.divFloor(&q, &r, &a, &b);
1857
1858 // n = q * d + r
1859 // -5 = 2 * -3 + 1
1860 const eq = 1;
1861 const er = -2;
1862
1863 debug.assert((try q.to(i32)) == eq);
1864 debug.assert((try r.to(i32)) == er);
1865}
1866
1867test "big.int div multi-multi with rem" {
1868 var a = try Int.initSet(al, 0x8888999911110000ffffeeeeddddccccbbbbaaaa9999);
1869 var b = try Int.initSet(al, 0x99990000111122223333);
1870
1871 var q = try Int.init(al);
1872 var r = try Int.init(al);
1873 try Int.divTrunc(&q, &r, &a, &b);
1874
1875 debug.assert((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b);
1876 debug.assert((try r.to(u128)) == 0x28de0acacd806823638);
1877}
1878
1879test "big.int div multi-multi no rem" {
1880 var a = try Int.initSet(al, 0x8888999911110000ffffeeeedb4fec200ee3a4286361);
1881 var b = try Int.initSet(al, 0x99990000111122223333);
1882
1883 var q = try Int.init(al);
1884 var r = try Int.init(al);
1885 try Int.divTrunc(&q, &r, &a, &b);
1886
1887 debug.assert((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b);
1888 debug.assert((try r.to(u128)) == 0);
1889}
1890
1891test "big.int div multi-multi (2 branch)" {
1892 var a = try Int.initSet(al, 0x866666665555555588888887777777761111111111111111);
1893 var b = try Int.initSet(al, 0x86666666555555554444444433333333);
1894
1895 var q = try Int.init(al);
1896 var r = try Int.init(al);
1897 try Int.divTrunc(&q, &r, &a, &b);
1898
1899 debug.assert((try q.to(u128)) == 0x10000000000000000);
1900 debug.assert((try r.to(u128)) == 0x44444443444444431111111111111111);
1901}
1902
1903test "big.int div multi-multi (3.1/3.3 branch)" {
1904 var a = try Int.initSet(al, 0x11111111111111111111111111111111111111111111111111111111111111);
1905 var b = try Int.initSet(al, 0x1111111111111111111111111111111111111111171);
1906
1907 var q = try Int.init(al);
1908 var r = try Int.init(al);
1909 try Int.divTrunc(&q, &r, &a, &b);
1910
1911 debug.assert((try q.to(u128)) == 0xfffffffffffffffffff);
1912 debug.assert((try r.to(u256)) == 0x1111111111111111111110b12222222222222222282);
1913}
1914
1915test "big.int shift-right single" {
1916 var a = try Int.initSet(al, 0xffff0000);
1917 try a.shiftRight(a, 16);
1918
1919 debug.assert((try a.to(u32)) == 0xffff);
1920}
1921
1922test "big.int shift-right multi" {
1923 var a = try Int.initSet(al, 0xffff0000eeee1111dddd2222cccc3333);
1924 try a.shiftRight(a, 67);
1925
1926 debug.assert((try a.to(u64)) == 0x1fffe0001dddc222);
1927}
1928
1929test "big.int shift-left single" {
1930 var a = try Int.initSet(al, 0xffff);
1931 try a.shiftLeft(a, 16);
1932
1933 debug.assert((try a.to(u64)) == 0xffff0000);
1934}
1935
1936test "big.int shift-left multi" {
1937 var a = try Int.initSet(al, 0x1fffe0001dddc222);
1938 try a.shiftLeft(a, 67);
1939
1940 debug.assert((try a.to(u128)) == 0xffff0000eeee11100000000000000000);
1941}
1942
1943test "big.int shift-right negative" {
1944 var a = try Int.init(al);
1945
1946 try a.shiftRight(-20, 2);
1947 debug.assert((try a.to(i32)) == -20 >> 2);
1948
1949 try a.shiftRight(-5, 10);
1950 debug.assert((try a.to(i32)) == -5 >> 10);
1951}
1952
1953test "big.int shift-left negative" {
1954 var a = try Int.init(al);
1955
1956 try a.shiftRight(-10, 1232);
1957 debug.assert((try a.to(i32)) == -10 >> 1232);
1958}
1959
1960test "big.int bitwise and simple" {
1961 var a = try Int.initSet(al, 0xffffffff11111111);
1962 var b = try Int.initSet(al, 0xeeeeeeee22222222);
1963
1964 try a.bitAnd(&a, &b);
1965
1966 debug.assert((try a.to(u64)) == 0xeeeeeeee00000000);
1967}
1968
1969test "big.int bitwise and multi-limb" {
1970 var a = try Int.initSet(al, @maxValue(Limb) + 1);
1971 var b = try Int.initSet(al, @maxValue(Limb));
1972
1973 try a.bitAnd(&a, &b);
1974
1975 debug.assert((try a.to(u128)) == 0);
1976}
1977
1978test "big.int bitwise xor simple" {
1979 var a = try Int.initSet(al, 0xffffffff11111111);
1980 var b = try Int.initSet(al, 0xeeeeeeee22222222);
1981
1982 try a.bitXor(&a, &b);
1983
1984 debug.assert((try a.to(u64)) == 0x1111111133333333);
1985}
1986
1987test "big.int bitwise xor multi-limb" {
1988 var a = try Int.initSet(al, @maxValue(Limb) + 1);
1989 var b = try Int.initSet(al, @maxValue(Limb));
1990
1991 try a.bitXor(&a, &b);
1992
1993 debug.assert((try a.to(DoubleLimb)) == (@maxValue(Limb) + 1) ^ @maxValue(Limb));
1994}
1995
1996test "big.int bitwise or simple" {
1997 var a = try Int.initSet(al, 0xffffffff11111111);
1998 var b = try Int.initSet(al, 0xeeeeeeee22222222);
1999
2000 try a.bitOr(&a, &b);
2001
2002 debug.assert((try a.to(u64)) == 0xffffffff33333333);
2003}
2004
2005test "big.int bitwise or multi-limb" {
2006 var a = try Int.initSet(al, @maxValue(Limb) + 1);
2007 var b = try Int.initSet(al, @maxValue(Limb));
2008
2009 try a.bitOr(&a, &b);
2010
2011 // TODO: big.int.cpp or is wrong on multi-limb.
2012 debug.assert((try a.to(DoubleLimb)) == (@maxValue(Limb) + 1) + @maxValue(Limb));
2013}
2014
2015test "big.int var args" {
2016 var a = try Int.initSet(al, 5);
2017
2018 try a.add(&a, 6);
2019 debug.assert((try a.to(u64)) == 11);
2020
2021 debug.assert(a.cmp(11) == 0);
2022 debug.assert(a.cmp(14) <= 0);
2023}
std/math/index.zig+12-1
......@@ -132,6 +132,8 @@ pub const tan = @import("tan.zig").tan;
132132pub const complex = @import("complex/index.zig");
133133pub const Complex = complex.Complex;
134134
135pub const big = @import("big/index.zig");
136
135137test "math" {
136138 _ = @import("nan.zig");
137139 _ = @import("isnan.zig");
......@@ -177,6 +179,8 @@ test "math" {
177179 _ = @import("tan.zig");
178180
179181 _ = @import("complex/index.zig");
182
183 _ = @import("big/index.zig");
180184}
181185
182186pub fn min(x: var, y: var) @typeOf(x + y) {
......@@ -306,7 +310,14 @@ test "math.rotl" {
306310}
307311
308312pub fn Log2Int(comptime T: type) type {
309 return @IntType(false, log2(T.bit_count));
313 // comptime ceil log2
314 comptime var count: usize = 0;
315 comptime var s = T.bit_count - 1;
316 inline while (s != 0) : (s >>= 1) {
317 count += 1;
318 }
319
320 return @IntType(false, count);
310321}
311322
312323test "math overflow functions" {
std/mem.zig+11-11
......@@ -304,20 +304,20 @@ pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, nee
304304}
305305
306306test "mem.indexOf" {
307 assert(??indexOf(u8, "one two three four", "four") == 14);
308 assert(??lastIndexOf(u8, "one two three two four", "two") == 14);
307 assert(indexOf(u8, "one two three four", "four").? == 14);
308 assert(lastIndexOf(u8, "one two three two four", "two").? == 14);
309309 assert(indexOf(u8, "one two three four", "gour") == null);
310310 assert(lastIndexOf(u8, "one two three four", "gour") == null);
311 assert(??indexOf(u8, "foo", "foo") == 0);
312 assert(??lastIndexOf(u8, "foo", "foo") == 0);
311 assert(indexOf(u8, "foo", "foo").? == 0);
312 assert(lastIndexOf(u8, "foo", "foo").? == 0);
313313 assert(indexOf(u8, "foo", "fool") == null);
314314 assert(lastIndexOf(u8, "foo", "lfoo") == null);
315315 assert(lastIndexOf(u8, "foo", "fool") == null);
316316
317 assert(??indexOf(u8, "foo foo", "foo") == 0);
318 assert(??lastIndexOf(u8, "foo foo", "foo") == 4);
319 assert(??lastIndexOfAny(u8, "boo, cat", "abo") == 6);
320 assert(??lastIndexOfScalar(u8, "boo", 'o') == 2);
317 assert(indexOf(u8, "foo foo", "foo").? == 0);
318 assert(lastIndexOf(u8, "foo foo", "foo").? == 4);
319 assert(lastIndexOfAny(u8, "boo, cat", "abo").? == 6);
320 assert(lastIndexOfScalar(u8, "boo", 'o').? == 2);
321321}
322322
323323/// Reads an integer from memory with size equal to bytes.len.
......@@ -432,9 +432,9 @@ pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator {
432432
433433test "mem.split" {
434434 var it = split(" abc def ghi ", " ");
435 assert(eql(u8, ??it.next(), "abc"));
436 assert(eql(u8, ??it.next(), "def"));
437 assert(eql(u8, ??it.next(), "ghi"));
435 assert(eql(u8, it.next().?, "abc"));
436 assert(eql(u8, it.next().?, "def"));
437 assert(eql(u8, it.next().?, "ghi"));
438438 assert(it.next() == null);
439439}
440440
std/os/child_process.zig+9-9
......@@ -156,7 +156,7 @@ pub const ChildProcess = struct {
156156 };
157157 }
158158 try self.waitUnwrappedWindows();
159 return ??self.term;
159 return self.term.?;
160160 }
161161
162162 pub fn killPosix(self: *ChildProcess) !Term {
......@@ -175,7 +175,7 @@ pub const ChildProcess = struct {
175175 };
176176 }
177177 self.waitUnwrapped();
178 return ??self.term;
178 return self.term.?;
179179 }
180180
181181 /// Blocks until child process terminates and then cleans up all resources.
......@@ -212,8 +212,8 @@ pub const ChildProcess = struct {
212212 defer Buffer.deinit(&stdout);
213213 defer Buffer.deinit(&stderr);
214214
215 var stdout_file_in_stream = io.FileInStream.init(&??child.stdout);
216 var stderr_file_in_stream = io.FileInStream.init(&??child.stderr);
215 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
216 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
217217
218218 try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
219219 try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size);
......@@ -232,7 +232,7 @@ pub const ChildProcess = struct {
232232 }
233233
234234 try self.waitUnwrappedWindows();
235 return ??self.term;
235 return self.term.?;
236236 }
237237
238238 fn waitPosix(self: *ChildProcess) !Term {
......@@ -242,7 +242,7 @@ pub const ChildProcess = struct {
242242 }
243243
244244 self.waitUnwrapped();
245 return ??self.term;
245 return self.term.?;
246246 }
247247
248248 pub fn deinit(self: *ChildProcess) void {
......@@ -619,13 +619,13 @@ pub const ChildProcess = struct {
619619 self.term = null;
620620
621621 if (self.stdin_behavior == StdIo.Pipe) {
622 os.close(??g_hChildStd_IN_Rd);
622 os.close(g_hChildStd_IN_Rd.?);
623623 }
624624 if (self.stderr_behavior == StdIo.Pipe) {
625 os.close(??g_hChildStd_ERR_Wr);
625 os.close(g_hChildStd_ERR_Wr.?);
626626 }
627627 if (self.stdout_behavior == StdIo.Pipe) {
628 os.close(??g_hChildStd_OUT_Wr);
628 os.close(g_hChildStd_OUT_Wr.?);
629629 }
630630 }
631631
std/os/darwin.zig+4-4
......@@ -327,7 +327,7 @@ pub fn raise(sig: i32) usize {
327327}
328328
329329pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
330 return errnoWrap(c.read(fd, @ptrCast([*]c_void, buf), nbyte));
330 return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
331331}
332332
333333pub fn stat(noalias path: [*]const u8, noalias buf: *stat) usize {
......@@ -335,17 +335,17 @@ pub fn stat(noalias path: [*]const u8, noalias buf: *stat) usize {
335335}
336336
337337pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
338 return errnoWrap(c.write(fd, @ptrCast([*]const c_void, buf), nbyte));
338 return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
339339}
340340
341341pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
342 const ptr_result = c.mmap(@ptrCast([*]c_void, address), length, @bitCast(c_int, c_uint(prot)), @bitCast(c_int, c_uint(flags)), fd, offset);
342 const ptr_result = c.mmap(@ptrCast(*c_void, address), length, @bitCast(c_int, c_uint(prot)), @bitCast(c_int, c_uint(flags)), fd, offset);
343343 const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
344344 return errnoWrap(isize_result);
345345}
346346
347347pub fn munmap(address: usize, length: usize) usize {
348 return errnoWrap(c.munmap(@intToPtr([*]c_void, address), length));
348 return errnoWrap(c.munmap(@intToPtr(*c_void, address), length));
349349}
350350
351351pub fn unlink(path: [*]const u8) usize {
std/os/file.zig+16-3
......@@ -96,7 +96,20 @@ pub const File = struct {
9696 return File{ .handle = handle };
9797 }
9898
99 pub fn access(allocator: *mem.Allocator, path: []const u8, file_mode: os.FileMode) !bool {
99 pub const AccessError = error{
100 PermissionDenied,
101 NotFound,
102 NameTooLong,
103 BadMode,
104 BadPathName,
105 Io,
106 SystemResources,
107 OutOfMemory,
108
109 Unexpected,
110 };
111
112 pub fn access(allocator: *mem.Allocator, path: []const u8, file_mode: os.FileMode) AccessError!bool {
100113 const path_with_null = try std.cstr.addNullByte(allocator, path);
101114 defer allocator.free(path_with_null);
102115
......@@ -123,7 +136,7 @@ pub const File = struct {
123136 }
124137 return true;
125138 } else if (is_windows) {
126 if (os.windows.PathFileExists(path_with_null.ptr) == os.windows.TRUE) {
139 if (os.windows.GetFileAttributesA(path_with_null.ptr) != os.windows.INVALID_FILE_ATTRIBUTES) {
127140 return true;
128141 }
129142
......@@ -334,7 +347,7 @@ pub const File = struct {
334347 while (index < buffer.len) {
335348 const want_read_count = windows.DWORD(math.min(windows.DWORD(@maxValue(windows.DWORD)), buffer.len - index));
336349 var amt_read: windows.DWORD = undefined;
337 if (windows.ReadFile(self.handle, @ptrCast([*]c_void, buffer.ptr + index), want_read_count, &amt_read, null) == 0) {
350 if (windows.ReadFile(self.handle, @ptrCast(*c_void, buffer.ptr + index), want_read_count, &amt_read, null) == 0) {
338351 const err = windows.GetLastError();
339352 return switch (err) {
340353 windows.ERROR.OPERATION_ABORTED => continue,
std/os/index.zig+213-93
......@@ -422,10 +422,10 @@ pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator:
422422
423423 const exe_path = argv[0];
424424 if (mem.indexOfScalar(u8, exe_path, '/') != null) {
425 return posixExecveErrnoToErr(posix.getErrno(posix.execve(??argv_buf[0], argv_buf.ptr, envp_buf.ptr)));
425 return posixExecveErrnoToErr(posix.getErrno(posix.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr)));
426426 }
427427
428 const PATH = getEnvPosix("PATH") ?? "/usr/local/bin:/bin/:/usr/bin";
428 const PATH = getEnvPosix("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
429429 // PATH.len because it is >= the largest search_path
430430 // +1 for the / to join the search path and exe_path
431431 // +1 for the null terminating byte
......@@ -490,7 +490,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
490490 errdefer result.deinit();
491491
492492 if (is_windows) {
493 const ptr = windows.GetEnvironmentStringsA() ?? return error.OutOfMemory;
493 const ptr = windows.GetEnvironmentStringsA() orelse return error.OutOfMemory;
494494 defer assert(windows.FreeEnvironmentStringsA(ptr) != 0);
495495
496496 var i: usize = 0;
......@@ -573,7 +573,7 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) ![]u8 {
573573 return allocator.shrink(u8, buf, result);
574574 }
575575 } else {
576 const result = getEnvPosix(key) ?? return error.EnvironmentVariableNotFound;
576 const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound;
577577 return mem.dupe(allocator, u8, result);
578578 }
579579}
......@@ -714,7 +714,7 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path:
714714 else => return err, // TODO zig should know this set does not include PathAlreadyExists
715715 }
716716
717 const dirname = os.path.dirname(new_path);
717 const dirname = os.path.dirname(new_path) orelse ".";
718718
719719 var rand_buf: [12]u8 = undefined;
720720 const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));
......@@ -734,7 +734,23 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path:
734734 }
735735}
736736
737pub fn deleteFile(allocator: *Allocator, file_path: []const u8) !void {
737pub const DeleteFileError = error{
738 FileNotFound,
739 AccessDenied,
740 FileBusy,
741 FileSystem,
742 IsDir,
743 SymLinkLoop,
744 NameTooLong,
745 NotDir,
746 SystemResources,
747 ReadOnlyFileSystem,
748 OutOfMemory,
749
750 Unexpected,
751};
752
753pub fn deleteFile(allocator: *Allocator, file_path: []const u8) DeleteFileError!void {
738754 if (builtin.os == Os.windows) {
739755 return deleteFileWindows(allocator, file_path);
740756 } else {
......@@ -844,14 +860,14 @@ pub const AtomicFile = struct {
844860
845861 var rand_buf: [12]u8 = undefined;
846862
847 const dirname_component_len = if (dirname.len == 0) 0 else dirname.len + 1;
863 const dirname_component_len = if (dirname) |d| d.len + 1 else 0;
848864 const tmp_path = try allocator.alloc(u8, dirname_component_len +
849865 base64.Base64Encoder.calcSize(rand_buf.len));
850866 errdefer allocator.free(tmp_path);
851867
852 if (dirname.len != 0) {
853 mem.copy(u8, tmp_path[0..], dirname);
854 tmp_path[dirname.len] = os.path.sep;
868 if (dirname) |dir| {
869 mem.copy(u8, tmp_path[0..], dir);
870 tmp_path[dir.len] = os.path.sep;
855871 }
856872
857873 while (true) {
......@@ -1019,37 +1035,66 @@ pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
10191035 }
10201036}
10211037
1038pub const DeleteDirError = error{
1039 AccessDenied,
1040 FileBusy,
1041 SymLinkLoop,
1042 NameTooLong,
1043 FileNotFound,
1044 SystemResources,
1045 NotDir,
1046 DirNotEmpty,
1047 ReadOnlyFileSystem,
1048 OutOfMemory,
1049
1050 Unexpected,
1051};
1052
10221053/// Returns ::error.DirNotEmpty if the directory is not empty.
10231054/// To delete a directory recursively, see ::deleteTree
1024pub fn deleteDir(allocator: *Allocator, dir_path: []const u8) !void {
1055pub fn deleteDir(allocator: *Allocator, dir_path: []const u8) DeleteDirError!void {
10251056 const path_buf = try allocator.alloc(u8, dir_path.len + 1);
10261057 defer allocator.free(path_buf);
10271058
10281059 mem.copy(u8, path_buf, dir_path);
10291060 path_buf[dir_path.len] = 0;
10301061
1031 const err = posix.getErrno(posix.rmdir(path_buf.ptr));
1032 if (err > 0) {
1033 return switch (err) {
1034 posix.EACCES, posix.EPERM => error.AccessDenied,
1035 posix.EBUSY => error.FileBusy,
1036 posix.EFAULT, posix.EINVAL => unreachable,
1037 posix.ELOOP => error.SymLinkLoop,
1038 posix.ENAMETOOLONG => error.NameTooLong,
1039 posix.ENOENT => error.FileNotFound,
1040 posix.ENOMEM => error.SystemResources,
1041 posix.ENOTDIR => error.NotDir,
1042 posix.EEXIST, posix.ENOTEMPTY => error.DirNotEmpty,
1043 posix.EROFS => error.ReadOnlyFileSystem,
1044 else => unexpectedErrorPosix(err),
1045 };
1062 switch (builtin.os) {
1063 Os.windows => {
1064 if (windows.RemoveDirectoryA(path_buf.ptr) == 0) {
1065 const err = windows.GetLastError();
1066 return switch (err) {
1067 windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,
1068 windows.ERROR.DIR_NOT_EMPTY => error.DirNotEmpty,
1069 else => unexpectedErrorWindows(err),
1070 };
1071 }
1072 },
1073 Os.linux, Os.macosx, Os.ios => {
1074 const err = posix.getErrno(posix.rmdir(path_buf.ptr));
1075 if (err > 0) {
1076 return switch (err) {
1077 posix.EACCES, posix.EPERM => error.AccessDenied,
1078 posix.EBUSY => error.FileBusy,
1079 posix.EFAULT, posix.EINVAL => unreachable,
1080 posix.ELOOP => error.SymLinkLoop,
1081 posix.ENAMETOOLONG => error.NameTooLong,
1082 posix.ENOENT => error.FileNotFound,
1083 posix.ENOMEM => error.SystemResources,
1084 posix.ENOTDIR => error.NotDir,
1085 posix.EEXIST, posix.ENOTEMPTY => error.DirNotEmpty,
1086 posix.EROFS => error.ReadOnlyFileSystem,
1087 else => unexpectedErrorPosix(err),
1088 };
1089 }
1090 },
1091 else => @compileError("unimplemented"),
10461092 }
10471093}
10481094
10491095/// Whether ::full_path describes a symlink, file, or directory, this function
10501096/// removes it. If it cannot be removed because it is a non-empty directory,
10511097/// this function recursively removes its entries and then tries again.
1052/// TODO non-recursive implementation
10531098const DeleteTreeError = error{
10541099 OutOfMemory,
10551100 AccessDenied,
......@@ -1128,7 +1173,7 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!
11281173 try full_entry_buf.resize(full_path.len + entry.name.len + 1);
11291174 const full_entry_path = full_entry_buf.toSlice();
11301175 mem.copy(u8, full_entry_path, full_path);
1131 full_entry_path[full_path.len] = '/';
1176 full_entry_path[full_path.len] = path.sep;
11321177 mem.copy(u8, full_entry_path[full_path.len + 1 ..], entry.name);
11331178
11341179 try deleteTree(allocator, full_entry_path);
......@@ -1139,16 +1184,29 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!
11391184}
11401185
11411186pub const Dir = struct {
1142 fd: i32,
1143 darwin_seek: darwin_seek_t,
1187 handle: Handle,
11441188 allocator: *Allocator,
1145 buf: []u8,
1146 index: usize,
1147 end_index: usize,
11481189
1149 const darwin_seek_t = switch (builtin.os) {
1150 Os.macosx, Os.ios => i64,
1151 else => void,
1190 pub const Handle = switch (builtin.os) {
1191 Os.macosx, Os.ios => struct {
1192 fd: i32,
1193 seek: i64,
1194 buf: []u8,
1195 index: usize,
1196 end_index: usize,
1197 },
1198 Os.linux => struct {
1199 fd: i32,
1200 buf: []u8,
1201 index: usize,
1202 end_index: usize,
1203 },
1204 Os.windows => struct {
1205 handle: windows.HANDLE,
1206 find_file_data: windows.WIN32_FIND_DATAA,
1207 first: bool,
1208 },
1209 else => @compileError("unimplemented"),
11521210 };
11531211
11541212 pub const Entry = struct {
......@@ -1168,81 +1226,122 @@ pub const Dir = struct {
11681226 };
11691227 };
11701228
1171 pub fn open(allocator: *Allocator, dir_path: []const u8) !Dir {
1172 const fd = switch (builtin.os) {
1173 Os.windows => @compileError("TODO support Dir.open for windows"),
1174 Os.linux => try posixOpen(allocator, dir_path, posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC, 0),
1175 Os.macosx, Os.ios => try posixOpen(
1176 allocator,
1177 dir_path,
1178 posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC,
1179 0,
1180 ),
1181 else => @compileError("Dir.open is not supported for this platform"),
1182 };
1183 const darwin_seek_init = switch (builtin.os) {
1184 Os.macosx, Os.ios => 0,
1185 else => {},
1186 };
1229 pub const OpenError = error{
1230 PathNotFound,
1231 NotDir,
1232 AccessDenied,
1233 FileTooBig,
1234 IsDir,
1235 SymLinkLoop,
1236 ProcessFdQuotaExceeded,
1237 NameTooLong,
1238 SystemFdQuotaExceeded,
1239 NoDevice,
1240 SystemResources,
1241 NoSpaceLeft,
1242 PathAlreadyExists,
1243 OutOfMemory,
1244
1245 Unexpected,
1246 };
1247
1248 pub fn open(allocator: *Allocator, dir_path: []const u8) OpenError!Dir {
11871249 return Dir{
11881250 .allocator = allocator,
1189 .fd = fd,
1190 .darwin_seek = darwin_seek_init,
1191 .index = 0,
1192 .end_index = 0,
1193 .buf = []u8{},
1251 .handle = switch (builtin.os) {
1252 Os.windows => blk: {
1253 var find_file_data: windows.WIN32_FIND_DATAA = undefined;
1254 const handle = try windows_util.windowsFindFirstFile(allocator, dir_path, &find_file_data);
1255 break :blk Handle{
1256 .handle = handle,
1257 .find_file_data = find_file_data, // TODO guaranteed copy elision
1258 .first = true,
1259 };
1260 },
1261 Os.macosx, Os.ios => Handle{
1262 .fd = try posixOpen(
1263 allocator,
1264 dir_path,
1265 posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC,
1266 0,
1267 ),
1268 .seek = 0,
1269 .index = 0,
1270 .end_index = 0,
1271 .buf = []u8{},
1272 },
1273 Os.linux => Handle{
1274 .fd = try posixOpen(
1275 allocator,
1276 dir_path,
1277 posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC,
1278 0,
1279 ),
1280 .index = 0,
1281 .end_index = 0,
1282 .buf = []u8{},
1283 },
1284 else => @compileError("unimplemented"),
1285 },
11941286 };
11951287 }
11961288
11971289 pub fn close(self: *Dir) void {
1198 self.allocator.free(self.buf);
1199 os.close(self.fd);
1290 switch (builtin.os) {
1291 Os.windows => {
1292 _ = windows.FindClose(self.handle.handle);
1293 },
1294 Os.macosx, Os.ios, Os.linux => {
1295 self.allocator.free(self.handle.buf);
1296 os.close(self.handle.fd);
1297 },
1298 else => @compileError("unimplemented"),
1299 }
12001300 }
12011301
12021302 /// Memory such as file names referenced in this returned entry becomes invalid
1203 /// with subsequent calls to next, as well as when this ::Dir is deinitialized.
1303 /// with subsequent calls to next, as well as when this `Dir` is deinitialized.
12041304 pub fn next(self: *Dir) !?Entry {
12051305 switch (builtin.os) {
12061306 Os.linux => return self.nextLinux(),
12071307 Os.macosx, Os.ios => return self.nextDarwin(),
12081308 Os.windows => return self.nextWindows(),
1209 else => @compileError("Dir.next not supported on " ++ @tagName(builtin.os)),
1309 else => @compileError("unimplemented"),
12101310 }
12111311 }
12121312
12131313 fn nextDarwin(self: *Dir) !?Entry {
12141314 start_over: while (true) {
1215 if (self.index >= self.end_index) {
1216 if (self.buf.len == 0) {
1217 self.buf = try self.allocator.alloc(u8, page_size);
1315 if (self.handle.index >= self.handle.end_index) {
1316 if (self.handle.buf.len == 0) {
1317 self.handle.buf = try self.allocator.alloc(u8, page_size);
12181318 }
12191319
12201320 while (true) {
1221 const result = posix.getdirentries64(self.fd, self.buf.ptr, self.buf.len, &self.darwin_seek);
1321 const result = posix.getdirentries64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek);
12221322 const err = posix.getErrno(result);
12231323 if (err > 0) {
12241324 switch (err) {
12251325 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
12261326 posix.EINVAL => {
1227 self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2);
1327 self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
12281328 continue;
12291329 },
12301330 else => return unexpectedErrorPosix(err),
12311331 }
12321332 }
12331333 if (result == 0) return null;
1234 self.index = 0;
1235 self.end_index = result;
1334 self.handle.index = 0;
1335 self.handle.end_index = result;
12361336 break;
12371337 }
12381338 }
1239 const darwin_entry = @ptrCast(*align(1) posix.dirent, &self.buf[self.index]);
1240 const next_index = self.index + darwin_entry.d_reclen;
1241 self.index = next_index;
1339 const darwin_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
1340 const next_index = self.handle.index + darwin_entry.d_reclen;
1341 self.handle.index = next_index;
12421342
12431343 const name = @ptrCast([*]u8, &darwin_entry.d_name)[0..darwin_entry.d_namlen];
12441344
1245 // skip . and .. entries
12461345 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
12471346 continue :start_over;
12481347 }
......@@ -1266,38 +1365,59 @@ pub const Dir = struct {
12661365 }
12671366
12681367 fn nextWindows(self: *Dir) !?Entry {
1269 @compileError("TODO support Dir.next for windows");
1368 while (true) {
1369 if (self.handle.first) {
1370 self.handle.first = false;
1371 } else {
1372 if (!try windows_util.windowsFindNextFile(self.handle.handle, &self.handle.find_file_data))
1373 return null;
1374 }
1375 const name = std.cstr.toSlice(self.handle.find_file_data.cFileName[0..].ptr);
1376 if (mem.eql(u8, name, ".") or mem.eql(u8, name, ".."))
1377 continue;
1378 const kind = blk: {
1379 const attrs = self.handle.find_file_data.dwFileAttributes;
1380 if (attrs & windows.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory;
1381 if (attrs & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) break :blk Entry.Kind.SymLink;
1382 if (attrs & windows.FILE_ATTRIBUTE_NORMAL != 0) break :blk Entry.Kind.File;
1383 break :blk Entry.Kind.Unknown;
1384 };
1385 return Entry{
1386 .name = name,
1387 .kind = kind,
1388 };
1389 }
12701390 }
12711391
12721392 fn nextLinux(self: *Dir) !?Entry {
12731393 start_over: while (true) {
1274 if (self.index >= self.end_index) {
1275 if (self.buf.len == 0) {
1276 self.buf = try self.allocator.alloc(u8, page_size);
1394 if (self.handle.index >= self.handle.end_index) {
1395 if (self.handle.buf.len == 0) {
1396 self.handle.buf = try self.allocator.alloc(u8, page_size);
12771397 }
12781398
12791399 while (true) {
1280 const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);
1400 const result = posix.getdents(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len);
12811401 const err = posix.getErrno(result);
12821402 if (err > 0) {
12831403 switch (err) {
12841404 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
12851405 posix.EINVAL => {
1286 self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2);
1406 self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
12871407 continue;
12881408 },
12891409 else => return unexpectedErrorPosix(err),
12901410 }
12911411 }
12921412 if (result == 0) return null;
1293 self.index = 0;
1294 self.end_index = result;
1413 self.handle.index = 0;
1414 self.handle.end_index = result;
12951415 break;
12961416 }
12971417 }
1298 const linux_entry = @ptrCast(*align(1) posix.dirent, &self.buf[self.index]);
1299 const next_index = self.index + linux_entry.d_reclen;
1300 self.index = next_index;
1418 const linux_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
1419 const next_index = self.handle.index + linux_entry.d_reclen;
1420 self.handle.index = next_index;
13011421
13021422 const name = cstr.toSlice(@ptrCast([*]u8, &linux_entry.d_name));
13031423
......@@ -1306,7 +1426,7 @@ pub const Dir = struct {
13061426 continue :start_over;
13071427 }
13081428
1309 const type_char = self.buf[next_index - 1];
1429 const type_char = self.handle.buf[next_index - 1];
13101430 const entry_kind = switch (type_char) {
13111431 posix.DT_BLK => Entry.Kind.BlockDevice,
13121432 posix.DT_CHR => Entry.Kind.CharacterDevice,
......@@ -1641,7 +1761,7 @@ pub const ArgIterator = struct {
16411761 if (builtin.os == Os.windows) {
16421762 return self.inner.next(allocator);
16431763 } else {
1644 return mem.dupe(allocator, u8, self.inner.next() ?? return null);
1764 return mem.dupe(allocator, u8, self.inner.next() orelse return null);
16451765 }
16461766 }
16471767
......@@ -1729,7 +1849,7 @@ test "windows arg parsing" {
17291849fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void {
17301850 var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line);
17311851 for (expected_args) |expected_arg| {
1732 const arg = ??it.next(debug.global_allocator) catch unreachable;
1852 const arg = it.next(debug.global_allocator).? catch unreachable;
17331853 assert(mem.eql(u8, arg, expected_arg));
17341854 }
17351855 assert(it.next(debug.global_allocator) == null);
......@@ -1845,13 +1965,13 @@ pub fn selfExeDirPath(allocator: *mem.Allocator) ![]u8 {
18451965 // the executable was in when it was run.
18461966 const full_exe_path = try readLink(allocator, "/proc/self/exe");
18471967 errdefer allocator.free(full_exe_path);
1848 const dir = path.dirname(full_exe_path);
1968 const dir = path.dirname(full_exe_path) orelse ".";
18491969 return allocator.shrink(u8, full_exe_path, dir.len);
18501970 },
18511971 Os.windows, Os.macosx, Os.ios => {
18521972 const self_exe_path = try selfExePath(allocator);
18531973 errdefer allocator.free(self_exe_path);
1854 const dirname = os.path.dirname(self_exe_path);
1974 const dirname = os.path.dirname(self_exe_path) orelse ".";
18551975 return allocator.shrink(u8, self_exe_path, dirname.len);
18561976 },
18571977 else => @compileError("unimplemented: std.os.selfExeDirPath for " ++ @tagName(builtin.os)),
......@@ -2362,7 +2482,7 @@ pub const Thread = struct {
23622482 },
23632483 builtin.Os.windows => struct {
23642484 handle: windows.HANDLE,
2365 alloc_start: [*]c_void,
2485 alloc_start: *c_void,
23662486 heap_handle: windows.HANDLE,
23672487 },
23682488 else => @compileError("Unsupported OS"),
......@@ -2457,9 +2577,9 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread
24572577 }
24582578 };
24592579
2460 const heap_handle = windows.GetProcessHeap() ?? return SpawnThreadError.OutOfMemory;
2580 const heap_handle = windows.GetProcessHeap() orelse return SpawnThreadError.OutOfMemory;
24612581 const byte_count = @alignOf(WinThread.OuterContext) + @sizeOf(WinThread.OuterContext);
2462 const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) ?? return SpawnThreadError.OutOfMemory;
2582 const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory;
24632583 errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0);
24642584 const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];
24652585 const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable;
......@@ -2468,7 +2588,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread
24682588 outer_context.thread.data.alloc_start = bytes_ptr;
24692589
24702590 const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);
2471 outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) ?? {
2591 outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse {
24722592 const err = windows.GetLastError();
24732593 return switch (err) {
24742594 else => os.unexpectedErrorWindows(err),
......@@ -2533,7 +2653,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread
25332653
25342654 // align to page
25352655 stack_end -= stack_end % os.page_size;
2536 assert(c.pthread_attr_setstack(&attr, @intToPtr([*]c_void, stack_addr), stack_end - stack_addr) == 0);
2656 assert(c.pthread_attr_setstack(&attr, @intToPtr(*c_void, stack_addr), stack_end - stack_addr) == 0);
25372657
25382658 const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg));
25392659 switch (err) {
std/os/linux/vdso.zig+5-5
......@@ -28,7 +28,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
2828 }
2929 }
3030 }
31 const dynv = maybe_dynv ?? return 0;
31 const dynv = maybe_dynv orelse return 0;
3232 if (base == @maxValue(usize)) return 0;
3333
3434 var maybe_strings: ?[*]u8 = null;
......@@ -52,9 +52,9 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
5252 }
5353 }
5454
55 const strings = maybe_strings ?? return 0;
56 const syms = maybe_syms ?? return 0;
57 const hashtab = maybe_hashtab ?? return 0;
55 const strings = maybe_strings orelse return 0;
56 const syms = maybe_syms orelse return 0;
57 const hashtab = maybe_hashtab orelse return 0;
5858 if (maybe_verdef == null) maybe_versym = null;
5959
6060 const OK_TYPES = (1 << elf.STT_NOTYPE | 1 << elf.STT_OBJECT | 1 << elf.STT_FUNC | 1 << elf.STT_COMMON);
......@@ -67,7 +67,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
6767 if (0 == syms[i].st_shndx) continue;
6868 if (!mem.eql(u8, name, cstr.toSliceConst(strings + syms[i].st_name))) continue;
6969 if (maybe_versym) |versym| {
70 if (!checkver(??maybe_verdef, versym[i], vername, strings))
70 if (!checkver(maybe_verdef.?, versym[i], vername, strings))
7171 continue;
7272 }
7373 return base + syms[i].st_value;
std/os/path.zig+44-30
......@@ -182,8 +182,8 @@ pub fn windowsParsePath(path: []const u8) WindowsPath {
182182 }
183183
184184 var it = mem.split(path, []u8{this_sep});
185 _ = (it.next() ?? return relative_path);
186 _ = (it.next() ?? return relative_path);
185 _ = (it.next() orelse return relative_path);
186 _ = (it.next() orelse return relative_path);
187187 return WindowsPath{
188188 .is_abs = isAbsoluteWindows(path),
189189 .kind = WindowsPath.Kind.NetworkShare,
......@@ -200,8 +200,8 @@ pub fn windowsParsePath(path: []const u8) WindowsPath {
200200 }
201201
202202 var it = mem.split(path, []u8{this_sep});
203 _ = (it.next() ?? return relative_path);
204 _ = (it.next() ?? return relative_path);
203 _ = (it.next() orelse return relative_path);
204 _ = (it.next() orelse return relative_path);
205205 return WindowsPath{
206206 .is_abs = isAbsoluteWindows(path),
207207 .kind = WindowsPath.Kind.NetworkShare,
......@@ -265,7 +265,7 @@ fn networkShareServersEql(ns1: []const u8, ns2: []const u8) bool {
265265 var it2 = mem.split(ns2, []u8{sep2});
266266
267267 // TODO ASCII is wrong, we actually need full unicode support to compare paths.
268 return asciiEqlIgnoreCase(??it1.next(), ??it2.next());
268 return asciiEqlIgnoreCase(it1.next().?, it2.next().?);
269269}
270270
271271fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8) bool {
......@@ -286,7 +286,7 @@ fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8
286286 var it2 = mem.split(p2, []u8{sep2});
287287
288288 // TODO ASCII is wrong, we actually need full unicode support to compare paths.
289 return asciiEqlIgnoreCase(??it1.next(), ??it2.next()) and asciiEqlIgnoreCase(??it1.next(), ??it2.next());
289 return asciiEqlIgnoreCase(it1.next().?, it2.next().?) and asciiEqlIgnoreCase(it1.next().?, it2.next().?);
290290 },
291291 }
292292}
......@@ -414,8 +414,8 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
414414 WindowsPath.Kind.NetworkShare => {
415415 result = try allocator.alloc(u8, max_size);
416416 var it = mem.split(paths[first_index], "/\\");
417 const server_name = ??it.next();
418 const other_name = ??it.next();
417 const server_name = it.next().?;
418 const other_name = it.next().?;
419419
420420 result[result_index] = '\\';
421421 result_index += 1;
......@@ -648,8 +648,8 @@ fn testResolvePosix(paths: []const []const u8) []u8 {
648648}
649649
650650/// If the path is a file in the current directory (no directory component)
651/// then the returned slice has .len = 0.
652pub fn dirname(path: []const u8) []const u8 {
651/// then returns null
652pub fn dirname(path: []const u8) ?[]const u8 {
653653 if (is_windows) {
654654 return dirnameWindows(path);
655655 } else {
......@@ -657,9 +657,9 @@ pub fn dirname(path: []const u8) []const u8 {
657657 }
658658}
659659
660pub fn dirnameWindows(path: []const u8) []const u8 {
660pub fn dirnameWindows(path: []const u8) ?[]const u8 {
661661 if (path.len == 0)
662 return path[0..0];
662 return null;
663663
664664 const root_slice = diskDesignatorWindows(path);
665665 if (path.len == root_slice.len)
......@@ -671,13 +671,13 @@ pub fn dirnameWindows(path: []const u8) []const u8 {
671671
672672 while ((path[end_index] == '/' or path[end_index] == '\\') and end_index > root_slice.len) {
673673 if (end_index == 0)
674 return path[0..0];
674 return null;
675675 end_index -= 1;
676676 }
677677
678678 while (path[end_index] != '/' and path[end_index] != '\\' and end_index > root_slice.len) {
679679 if (end_index == 0)
680 return path[0..0];
680 return null;
681681 end_index -= 1;
682682 }
683683
......@@ -685,12 +685,15 @@ pub fn dirnameWindows(path: []const u8) []const u8 {
685685 end_index += 1;
686686 }
687687
688 if (end_index == 0)
689 return null;
690
688691 return path[0..end_index];
689692}
690693
691pub fn dirnamePosix(path: []const u8) []const u8 {
694pub fn dirnamePosix(path: []const u8) ?[]const u8 {
692695 if (path.len == 0)
693 return path[0..0];
696 return null;
694697
695698 var end_index: usize = path.len - 1;
696699 while (path[end_index] == '/') {
......@@ -701,13 +704,16 @@ pub fn dirnamePosix(path: []const u8) []const u8 {
701704
702705 while (path[end_index] != '/') {
703706 if (end_index == 0)
704 return path[0..0];
707 return null;
705708 end_index -= 1;
706709 }
707710
708711 if (end_index == 0 and path[end_index] == '/')
709712 return path[0..1];
710713
714 if (end_index == 0)
715 return null;
716
711717 return path[0..end_index];
712718}
713719
......@@ -717,10 +723,10 @@ test "os.path.dirnamePosix" {
717723 testDirnamePosix("/a", "/");
718724 testDirnamePosix("/", "/");
719725 testDirnamePosix("////", "/");
720 testDirnamePosix("", "");
721 testDirnamePosix("a", "");
722 testDirnamePosix("a/", "");
723 testDirnamePosix("a//", "");
726 testDirnamePosix("", null);
727 testDirnamePosix("a", null);
728 testDirnamePosix("a/", null);
729 testDirnamePosix("a//", null);
724730}
725731
726732test "os.path.dirnameWindows" {
......@@ -742,7 +748,7 @@ test "os.path.dirnameWindows" {
742748 testDirnameWindows("c:foo\\bar", "c:foo");
743749 testDirnameWindows("c:foo\\bar\\", "c:foo");
744750 testDirnameWindows("c:foo\\bar\\baz", "c:foo\\bar");
745 testDirnameWindows("file:stream", "");
751 testDirnameWindows("file:stream", null);
746752 testDirnameWindows("dir\\file:stream", "dir");
747753 testDirnameWindows("\\\\unc\\share", "\\\\unc\\share");
748754 testDirnameWindows("\\\\unc\\share\\foo", "\\\\unc\\share\\");
......@@ -753,18 +759,26 @@ test "os.path.dirnameWindows" {
753759 testDirnameWindows("/a/b/", "/a");
754760 testDirnameWindows("/a/b", "/a");
755761 testDirnameWindows("/a", "/");
756 testDirnameWindows("", "");
762 testDirnameWindows("", null);
757763 testDirnameWindows("/", "/");
758764 testDirnameWindows("////", "/");
759 testDirnameWindows("foo", "");
765 testDirnameWindows("foo", null);
760766}
761767
762fn testDirnamePosix(input: []const u8, expected_output: []const u8) void {
763 assert(mem.eql(u8, dirnamePosix(input), expected_output));
768fn testDirnamePosix(input: []const u8, expected_output: ?[]const u8) void {
769 if (dirnamePosix(input)) |output| {
770 assert(mem.eql(u8, output, expected_output.?));
771 } else {
772 assert(expected_output == null);
773 }
764774}
765775
766fn testDirnameWindows(input: []const u8, expected_output: []const u8) void {
767 assert(mem.eql(u8, dirnameWindows(input), expected_output));
776fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) void {
777 if (dirnameWindows(input)) |output| {
778 assert(mem.eql(u8, output, expected_output.?));
779 } else {
780 assert(expected_output == null);
781 }
768782}
769783
770784pub fn basename(path: []const u8) []const u8 {
......@@ -923,7 +937,7 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8)
923937 var from_it = mem.split(resolved_from, "/\\");
924938 var to_it = mem.split(resolved_to, "/\\");
925939 while (true) {
926 const from_component = from_it.next() ?? return mem.dupe(allocator, u8, to_it.rest());
940 const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest());
927941 const to_rest = to_it.rest();
928942 if (to_it.next()) |to_component| {
929943 // TODO ASCII is wrong, we actually need full unicode support to compare paths.
......@@ -974,7 +988,7 @@ pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![
974988 var from_it = mem.split(resolved_from, "/");
975989 var to_it = mem.split(resolved_to, "/");
976990 while (true) {
977 const from_component = from_it.next() ?? return mem.dupe(allocator, u8, to_it.rest());
991 const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest());
978992 const to_rest = to_it.rest();
979993 if (to_it.next()) |to_component| {
980994 if (mem.eql(u8, from_component, to_component))
std/os/test.zig-9
......@@ -10,11 +10,6 @@ const AtomicRmwOp = builtin.AtomicRmwOp;
1010const AtomicOrder = builtin.AtomicOrder;
1111
1212test "makePath, put some files in it, deleteTree" {
13 if (builtin.os == builtin.Os.windows) {
14 // TODO implement os.Dir for windows
15 // https://github.com/ziglang/zig/issues/709
16 return;
17 }
1813 try os.makePath(a, "os_test_tmp/b/c");
1914 try io.writeFile(a, "os_test_tmp/b/c/file.txt", "nonsense");
2015 try io.writeFile(a, "os_test_tmp/b/file2.txt", "blah");
......@@ -27,10 +22,6 @@ test "makePath, put some files in it, deleteTree" {
2722}
2823
2924test "access file" {
30 if (builtin.os == builtin.Os.windows) {
31 return;
32 }
33
3425 try os.makePath(a, "os_test_tmp");
3526 if (os.File.access(a, "os_test_tmp/file.txt", os.default_file_mode)) |ok| {
3627 unreachable;
std/os/time.zig+4-2
......@@ -68,11 +68,13 @@ pub const milliTimestamp = switch (builtin.os) {
6868fn milliTimestampWindows() u64 {
6969 //FileTime has a granularity of 100 nanoseconds
7070 // and uses the NTFS/Windows epoch
71 var ft: i64 = undefined;
71 var ft: windows.FILETIME = undefined;
7272 windows.GetSystemTimeAsFileTime(&ft);
7373 const hns_per_ms = (ns_per_s / 100) / ms_per_s;
7474 const epoch_adj = epoch.windows * ms_per_s;
75 return u64(@divFloor(ft, hns_per_ms) + epoch_adj);
75
76 const ft64 = (u64(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
77 return @divFloor(ft64, hns_per_ms) - -epoch_adj;
7678}
7779
7880fn milliTimestampDarwin() u64 {
std/os/windows/index.zig+52-14
......@@ -1,3 +1,7 @@
1test "import" {
2 _ = @import("util.zig");
3}
4
15pub const ERROR = @import("error.zig");
26
37pub extern "advapi32" stdcallcc fn CryptAcquireContextA(
......@@ -61,6 +65,10 @@ pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) BOOL;
6165
6266pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) noreturn;
6367
68pub extern "kernel32" stdcallcc fn FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: *WIN32_FIND_DATAA) HANDLE;
69pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL;
70pub extern "kernel32" stdcallcc fn FindNextFileA(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAA) BOOL;
71
6472pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL;
6573
6674pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;
......@@ -77,6 +85,8 @@ pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCo
7785
7886pub extern "kernel32" stdcallcc fn GetFileSizeEx(hFile: HANDLE, lpFileSize: *LARGE_INTEGER) BOOL;
7987
88pub extern "kernel32" stdcallcc fn GetFileAttributesA(lpFileName: LPCSTR) DWORD;
89
8090pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: LPSTR, nSize: DWORD) DWORD;
8191
8292pub extern "kernel32" stdcallcc fn GetLastError() DWORD;
......@@ -97,21 +107,21 @@ pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(
97107
98108pub extern "kernel32" stdcallcc fn GetProcessHeap() ?HANDLE;
99109
100pub extern "kernel32" stdcallcc fn GetSystemTimeAsFileTime(?*FILETIME) void;
110pub extern "kernel32" stdcallcc fn GetSystemTimeAsFileTime(*FILETIME) void;
101111
102112pub extern "kernel32" stdcallcc fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) ?HANDLE;
103113pub extern "kernel32" stdcallcc fn HeapDestroy(hHeap: HANDLE) BOOL;
104pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: [*]c_void, dwBytes: SIZE_T) ?[*]c_void;
105pub extern "kernel32" stdcallcc fn HeapSize(hHeap: HANDLE, dwFlags: DWORD, lpMem: [*]const c_void) SIZE_T;
106pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: [*]const c_void) BOOL;
114pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void, dwBytes: SIZE_T) ?*c_void;
115pub extern "kernel32" stdcallcc fn HeapSize(hHeap: HANDLE, dwFlags: DWORD, lpMem: *const c_void) SIZE_T;
116pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: *const c_void) BOOL;
107117pub extern "kernel32" stdcallcc fn HeapCompact(hHeap: HANDLE, dwFlags: DWORD) SIZE_T;
108118pub extern "kernel32" stdcallcc fn HeapSummary(hHeap: HANDLE, dwFlags: DWORD, lpSummary: LPHEAP_SUMMARY) BOOL;
109119
110120pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) ?HANDLE;
111121
112pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) ?[*]c_void;
122pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) ?*c_void;
113123
114pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: [*]c_void) BOOL;
124pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void) BOOL;
115125
116126pub extern "kernel32" stdcallcc fn MoveFileExA(
117127 lpExistingFileName: LPCSTR,
......@@ -123,16 +133,16 @@ pub extern "kernel32" stdcallcc fn QueryPerformanceCounter(lpPerformanceCount: *
123133
124134pub extern "kernel32" stdcallcc fn QueryPerformanceFrequency(lpFrequency: *LARGE_INTEGER) BOOL;
125135
126pub extern "kernel32" stdcallcc fn PathFileExists(pszPath: ?LPCTSTR) BOOL;
127
128136pub extern "kernel32" stdcallcc fn ReadFile(
129137 in_hFile: HANDLE,
130 out_lpBuffer: [*]c_void,
138 out_lpBuffer: *c_void,
131139 in_nNumberOfBytesToRead: DWORD,
132140 out_lpNumberOfBytesRead: *DWORD,
133141 in_out_lpOverlapped: ?*OVERLAPPED,
134142) BOOL;
135143
144pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL;
145
136146pub extern "kernel32" stdcallcc fn SetFilePointerEx(
137147 in_fFile: HANDLE,
138148 in_liDistanceToMove: LARGE_INTEGER,
......@@ -150,7 +160,7 @@ pub extern "kernel32" stdcallcc fn WaitForSingleObject(hHandle: HANDLE, dwMillis
150160
151161pub extern "kernel32" stdcallcc fn WriteFile(
152162 in_hFile: HANDLE,
153 in_lpBuffer: [*]const c_void,
163 in_lpBuffer: *const c_void,
154164 in_nNumberOfBytesToWrite: DWORD,
155165 out_lpNumberOfBytesWritten: ?*DWORD,
156166 in_out_lpOverlapped: ?*OVERLAPPED,
......@@ -163,6 +173,8 @@ pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL;
163173
164174pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) c_int;
165175
176pub extern "shlwapi" stdcallcc fn PathFileExistsA(pszPath: ?LPCTSTR) BOOL;
177
166178pub const PROV_RSA_FULL = 1;
167179
168180pub const BOOL = c_int;
......@@ -196,7 +208,6 @@ pub const UNICODE = false;
196208pub const WCHAR = u16;
197209pub const WORD = u16;
198210pub const LARGE_INTEGER = i64;
199pub const FILETIME = i64;
200211
201212pub const TRUE = 1;
202213pub const FALSE = 0;
......@@ -212,6 +223,8 @@ pub const STD_ERROR_HANDLE = @maxValue(DWORD) - 12 + 1;
212223
213224pub const INVALID_HANDLE_VALUE = @intToPtr(HANDLE, @maxValue(usize));
214225
226pub const INVALID_FILE_ATTRIBUTES = DWORD(@maxValue(DWORD));
227
215228pub const OVERLAPPED = extern struct {
216229 Internal: ULONG_PTR,
217230 InternalHigh: ULONG_PTR,
......@@ -293,13 +306,24 @@ pub const OPEN_EXISTING = 3;
293306pub const TRUNCATE_EXISTING = 5;
294307
295308pub const FILE_ATTRIBUTE_ARCHIVE = 0x20;
309pub const FILE_ATTRIBUTE_COMPRESSED = 0x800;
310pub const FILE_ATTRIBUTE_DEVICE = 0x40;
311pub const FILE_ATTRIBUTE_DIRECTORY = 0x10;
296312pub const FILE_ATTRIBUTE_ENCRYPTED = 0x4000;
297313pub const FILE_ATTRIBUTE_HIDDEN = 0x2;
314pub const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000;
298315pub const FILE_ATTRIBUTE_NORMAL = 0x80;
316pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000;
317pub const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000;
299318pub const FILE_ATTRIBUTE_OFFLINE = 0x1000;
300319pub const FILE_ATTRIBUTE_READONLY = 0x1;
320pub const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000;
321pub const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000;
322pub const FILE_ATTRIBUTE_REPARSE_POINT = 0x400;
323pub const FILE_ATTRIBUTE_SPARSE_FILE = 0x200;
301324pub const FILE_ATTRIBUTE_SYSTEM = 0x4;
302325pub const FILE_ATTRIBUTE_TEMPORARY = 0x100;
326pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000;
303327
304328pub const PROCESS_INFORMATION = extern struct {
305329 hProcess: HANDLE,
......@@ -372,6 +396,20 @@ pub const HEAP_NO_SERIALIZE = 0x00000001;
372396pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD;
373397pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
374398
375test "import" {
376 _ = @import("util.zig");
377}
399pub const WIN32_FIND_DATAA = extern struct {
400 dwFileAttributes: DWORD,
401 ftCreationTime: FILETIME,
402 ftLastAccessTime: FILETIME,
403 ftLastWriteTime: FILETIME,
404 nFileSizeHigh: DWORD,
405 nFileSizeLow: DWORD,
406 dwReserved0: DWORD,
407 dwReserved1: DWORD,
408 cFileName: [260]CHAR,
409 cAlternateFileName: [14]CHAR,
410};
411
412pub const FILETIME = extern struct {
413 dwLowDateTime: DWORD,
414 dwHighDateTime: DWORD,
415};
std/os/windows/util.zig+41-2
......@@ -42,7 +42,7 @@ pub const WriteError = error{
4242};
4343
4444pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) WriteError!void {
45 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) {
4646 const err = windows.GetLastError();
4747 return switch (err) {
4848 windows.ERROR.INVALID_USER_BUFFER => WriteError.SystemResources,
......@@ -153,7 +153,7 @@ pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap)
153153pub fn windowsLoadDll(allocator: *mem.Allocator, dll_path: []const u8) !windows.HMODULE {
154154 const padded_buff = try cstr.addNullByte(allocator, dll_path);
155155 defer allocator.free(padded_buff);
156 return windows.LoadLibraryA(padded_buff.ptr) ?? error.DllNotFound;
156 return windows.LoadLibraryA(padded_buff.ptr) orelse error.DllNotFound;
157157}
158158
159159pub fn windowsUnloadDll(hModule: windows.HMODULE) void {
......@@ -170,3 +170,42 @@ test "InvalidDll" {
170170 return;
171171 };
172172}
173
174pub fn windowsFindFirstFile(
175 allocator: *mem.Allocator,
176 dir_path: []const u8,
177 find_file_data: *windows.WIN32_FIND_DATAA,
178) !windows.HANDLE {
179 const wild_and_null = []u8{ '\\', '*', 0 };
180 const path_with_wild_and_null = try allocator.alloc(u8, dir_path.len + wild_and_null.len);
181 defer allocator.free(path_with_wild_and_null);
182
183 mem.copy(u8, path_with_wild_and_null, dir_path);
184 mem.copy(u8, path_with_wild_and_null[dir_path.len..], wild_and_null);
185
186 const handle = windows.FindFirstFileA(path_with_wild_and_null.ptr, find_file_data);
187
188 if (handle == windows.INVALID_HANDLE_VALUE) {
189 const err = windows.GetLastError();
190 switch (err) {
191 windows.ERROR.FILE_NOT_FOUND,
192 windows.ERROR.PATH_NOT_FOUND,
193 => return error.PathNotFound,
194 else => return os.unexpectedErrorWindows(err),
195 }
196 }
197
198 return handle;
199}
200
201/// Returns `true` if there was another file, `false` otherwise.
202pub fn windowsFindNextFile(handle: windows.HANDLE, find_file_data: *windows.WIN32_FIND_DATAA) !bool {
203 if (windows.FindNextFileA(handle, find_file_data) == 0) {
204 const err = windows.GetLastError();
205 return switch (err) {
206 windows.ERROR.NO_MORE_FILES => false,
207 else => os.unexpectedErrorWindows(err),
208 };
209 }
210 return true;
211}
std/segmented_list.zig+4-4
......@@ -364,7 +364,7 @@ fn testSegmentedList(comptime prealloc: usize, allocator: *Allocator) !void {
364364 assert(x == 0);
365365 }
366366
367 assert(??list.pop() == 100);
367 assert(list.pop().? == 100);
368368 assert(list.len == 99);
369369
370370 try list.pushMany([]i32{
......@@ -373,9 +373,9 @@ fn testSegmentedList(comptime prealloc: usize, allocator: *Allocator) !void {
373373 3,
374374 });
375375 assert(list.len == 102);
376 assert(??list.pop() == 3);
377 assert(??list.pop() == 2);
378 assert(??list.pop() == 1);
376 assert(list.pop().? == 3);
377 assert(list.pop().? == 2);
378 assert(list.pop().? == 1);
379379 assert(list.len == 99);
380380
381381 try list.pushMany([]const i32{});
std/special/bootstrap.zig+4-4
......@@ -51,13 +51,13 @@ extern fn WinMainCRTStartup() noreturn {
5151
5252// TODO https://github.com/ziglang/zig/issues/265
5353fn posixCallMainAndExit() noreturn {
54 const argc = argc_ptr.*;
54 const argc = argc_ptr[0];
5555 const argv = @ptrCast([*][*]u8, argc_ptr + 1);
5656
57 const envp_nullable = @ptrCast([*]?[*]u8, argv + argc + 1);
57 const envp_optional = @ptrCast([*]?[*]u8, argv + argc + 1);
5858 var envp_count: usize = 0;
59 while (envp_nullable[envp_count]) |_| : (envp_count += 1) {}
60 const envp = @ptrCast([*][*]u8, envp_nullable)[0..envp_count];
59 while (envp_optional[envp_count]) |_| : (envp_count += 1) {}
60 const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count];
6161 if (builtin.os == builtin.Os.linux) {
6262 const auxv = @ptrCast([*]usize, envp.ptr + envp_count + 1);
6363 var i: usize = 0;
std/special/build_runner.zig+5-5
......@@ -27,15 +27,15 @@ pub fn main() !void {
2727 // skip my own exe name
2828 _ = arg_it.skip();
2929
30 const zig_exe = try unwrapArg(arg_it.next(allocator) ?? {
30 const zig_exe = try unwrapArg(arg_it.next(allocator) orelse {
3131 warn("Expected first argument to be path to zig compiler\n");
3232 return error.InvalidArgs;
3333 });
34 const build_root = try unwrapArg(arg_it.next(allocator) ?? {
34 const build_root = try unwrapArg(arg_it.next(allocator) orelse {
3535 warn("Expected second argument to be build root directory path\n");
3636 return error.InvalidArgs;
3737 });
38 const cache_root = try unwrapArg(arg_it.next(allocator) ?? {
38 const cache_root = try unwrapArg(arg_it.next(allocator) orelse {
3939 warn("Expected third argument to be cache root directory path\n");
4040 return error.InvalidArgs;
4141 });
......@@ -84,12 +84,12 @@ pub fn main() !void {
8484 } else if (mem.eql(u8, arg, "--help")) {
8585 return usage(&builder, false, try stdout_stream);
8686 } else if (mem.eql(u8, arg, "--prefix")) {
87 prefix = try unwrapArg(arg_it.next(allocator) ?? {
87 prefix = try unwrapArg(arg_it.next(allocator) orelse {
8888 warn("Expected argument after --prefix\n\n");
8989 return usageAndErr(&builder, false, try stderr_stream);
9090 });
9191 } else if (mem.eql(u8, arg, "--search-prefix")) {
92 const search_prefix = try unwrapArg(arg_it.next(allocator) ?? {
92 const search_prefix = try unwrapArg(arg_it.next(allocator) orelse {
9393 warn("Expected argument after --search-prefix\n\n");
9494 return usageAndErr(&builder, false, try stderr_stream);
9595 });
std/special/builtin.zig+4-4
......@@ -19,7 +19,7 @@ export fn memset(dest: ?[*]u8, c: u8, n: usize) ?[*]u8 {
1919
2020 var index: usize = 0;
2121 while (index != n) : (index += 1)
22 (??dest)[index] = c;
22 dest.?[index] = c;
2323
2424 return dest;
2525}
......@@ -29,7 +29,7 @@ export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) ?[*]
2929
3030 var index: usize = 0;
3131 while (index != n) : (index += 1)
32 (??dest)[index] = (??src)[index];
32 dest.?[index] = src.?[index];
3333
3434 return dest;
3535}
......@@ -40,13 +40,13 @@ export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8 {
4040 if (@ptrToInt(dest) < @ptrToInt(src)) {
4141 var index: usize = 0;
4242 while (index != n) : (index += 1) {
43 (??dest)[index] = (??src)[index];
43 dest.?[index] = src.?[index];
4444 }
4545 } else {
4646 var index = n;
4747 while (index != 0) {
4848 index -= 1;
49 (??dest)[index] = (??src)[index];
49 dest.?[index] = src.?[index];
5050 }
5151 }
5252
std/special/compiler_rt/divti3.zig created+26
......@@ -0,0 +1,26 @@
1const udivmod = @import("udivmod.zig").udivmod;
2const builtin = @import("builtin");
3const compiler_rt = @import("index.zig");
4
5pub extern fn __divti3(a: i128, b: i128) i128 {
6 @setRuntimeSafety(builtin.is_test);
7
8 const s_a = a >> (i128.bit_count - 1);
9 const s_b = b >> (i128.bit_count - 1);
10
11 const an = (a ^ s_a) -% s_a;
12 const bn = (b ^ s_b) -% s_b;
13
14 const r = udivmod(u128, @bitCast(u128, an), @bitCast(u128, bn), null);
15 const s = s_a ^ s_b;
16 return (i128(r) ^ s) -% s;
17}
18
19pub extern fn __divti3_windows_x86_64(a: *const i128, b: *const i128) void {
20 @setRuntimeSafety(builtin.is_test);
21 compiler_rt.setXmm0(i128, __divti3(a.*, b.*));
22}
23
24test "import divti3" {
25 _ = @import("divti3_test.zig");
26}
std/special/compiler_rt/divti3_test.zig created+21
......@@ -0,0 +1,21 @@
1const __divti3 = @import("divti3.zig").__divti3;
2const assert = @import("std").debug.assert;
3
4fn test__divti3(a: i128, b: i128, expected: i128) void {
5 const x = __divti3(a, b);
6 assert(x == expected);
7}
8
9test "divti3" {
10 test__divti3(0, 1, 0);
11 test__divti3(0, -1, 0);
12 test__divti3(2, 1, 2);
13 test__divti3(2, -1, -2);
14 test__divti3(-2, 1, -2);
15 test__divti3(-2, -1, 2);
16
17 test__divti3(@bitCast(i128, u128(0x8 << 124)), 1, @bitCast(i128, u128(0x8 << 124)));
18 test__divti3(@bitCast(i128, u128(0x8 << 124)), -1, @bitCast(i128, u128(0x8 << 124)));
19 test__divti3(@bitCast(i128, u128(0x8 << 124)), -2, @bitCast(i128, u128(0x4 << 124)));
20 test__divti3(@bitCast(i128, u128(0x8 << 124)), 2, @bitCast(i128, u128(0xc << 124)));
21}
std/special/compiler_rt/index.zig+4
......@@ -58,6 +58,8 @@ comptime {
5858 @export("__chkstk", __chkstk, strong_linkage);
5959 @export("___chkstk_ms", ___chkstk_ms, linkage);
6060 }
61 @export("__divti3", @import("divti3.zig").__divti3_windows_x86_64, linkage);
62 @export("__muloti4", @import("muloti4.zig").__muloti4_windows_x86_64, linkage);
6163 @export("__udivti3", @import("udivti3.zig").__udivti3_windows_x86_64, linkage);
6264 @export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4_windows_x86_64, linkage);
6365 @export("__umodti3", @import("umodti3.zig").__umodti3_windows_x86_64, linkage);
......@@ -65,6 +67,8 @@ comptime {
6567 else => {},
6668 }
6769 } else {
70 @export("__divti3", @import("divti3.zig").__divti3, linkage);
71 @export("__muloti4", @import("muloti4.zig").__muloti4, linkage);
6872 @export("__udivti3", @import("udivti3.zig").__udivti3, linkage);
6973 @export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4, linkage);
7074 @export("__umodti3", @import("umodti3.zig").__umodti3, linkage);
std/special/compiler_rt/muloti4.zig created+55
......@@ -0,0 +1,55 @@
1const udivmod = @import("udivmod.zig").udivmod;
2const builtin = @import("builtin");
3const compiler_rt = @import("index.zig");
4
5pub extern fn __muloti4(a: i128, b: i128, overflow: *c_int) i128 {
6 @setRuntimeSafety(builtin.is_test);
7
8 const min = @bitCast(i128, u128(1 << (i128.bit_count - 1)));
9 const max = ~min;
10 overflow.* = 0;
11
12 const r = a *% b;
13 if (a == min) {
14 if (b != 0 and b != 1) {
15 overflow.* = 1;
16 }
17 return r;
18 }
19 if (b == min) {
20 if (a != 0 and a != 1) {
21 overflow.* = 1;
22 }
23 return r;
24 }
25
26 const sa = a >> (i128.bit_count - 1);
27 const abs_a = (a ^ sa) -% sa;
28 const sb = b >> (i128.bit_count - 1);
29 const abs_b = (b ^ sb) -% sb;
30
31 if (abs_a < 2 or abs_b < 2) {
32 return r;
33 }
34
35 if (sa == sb) {
36 if (abs_a > @divFloor(max, abs_b)) {
37 overflow.* = 1;
38 }
39 } else {
40 if (abs_a > @divFloor(min, -abs_b)) {
41 overflow.* = 1;
42 }
43 }
44
45 return r;
46}
47
48pub extern fn __muloti4_windows_x86_64(a: *const i128, b: *const i128, overflow: *c_int) void {
49 @setRuntimeSafety(builtin.is_test);
50 compiler_rt.setXmm0(i128, __muloti4(a.*, b.*, overflow));
51}
52
53test "import muloti4" {
54 _ = @import("muloti4_test.zig");
55}
std/special/compiler_rt/muloti4_test.zig created+76
......@@ -0,0 +1,76 @@
1const __muloti4 = @import("muloti4.zig").__muloti4;
2const assert = @import("std").debug.assert;
3
4fn test__muloti4(a: i128, b: i128, expected: i128, expected_overflow: c_int) void {
5 var overflow: c_int = undefined;
6 const x = __muloti4(a, b, &overflow);
7 assert(overflow == expected_overflow and (expected_overflow != 0 or x == expected));
8}
9
10test "muloti4" {
11 test__muloti4(0, 0, 0, 0);
12 test__muloti4(0, 1, 0, 0);
13 test__muloti4(1, 0, 0, 0);
14 test__muloti4(0, 10, 0, 0);
15 test__muloti4(10, 0, 0, 0);
16
17 test__muloti4(0, 81985529216486895, 0, 0);
18 test__muloti4(81985529216486895, 0, 0, 0);
19
20 test__muloti4(0, -1, 0, 0);
21 test__muloti4(-1, 0, 0, 0);
22 test__muloti4(0, -10, 0, 0);
23 test__muloti4(-10, 0, 0, 0);
24 test__muloti4(0, -81985529216486895, 0, 0);
25 test__muloti4(-81985529216486895, 0, 0, 0);
26
27 test__muloti4(3037000499, 3037000499, 9223372030926249001, 0);
28 test__muloti4(-3037000499, 3037000499, -9223372030926249001, 0);
29 test__muloti4(3037000499, -3037000499, -9223372030926249001, 0);
30 test__muloti4(-3037000499, -3037000499, 9223372030926249001, 0);
31
32 test__muloti4(4398046511103, 2097152, 9223372036852678656, 0);
33 test__muloti4(-4398046511103, 2097152, -9223372036852678656, 0);
34 test__muloti4(4398046511103, -2097152, -9223372036852678656, 0);
35 test__muloti4(-4398046511103, -2097152, 9223372036852678656, 0);
36
37 test__muloti4(2097152, 4398046511103, 9223372036852678656, 0);
38 test__muloti4(-2097152, 4398046511103, -9223372036852678656, 0);
39 test__muloti4(2097152, -4398046511103, -9223372036852678656, 0);
40 test__muloti4(-2097152, -4398046511103, 9223372036852678656, 0);
41
42 test__muloti4(@bitCast(i128, u128(0x00000000000000B504F333F9DE5BE000)), @bitCast(i128, u128(0x000000000000000000B504F333F9DE5B)), @bitCast(i128, u128(0x7FFFFFFFFFFFF328DF915DA296E8A000)), 0);
43 test__muloti4(@bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), -2, @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
44 test__muloti4(-2, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
45
46 test__muloti4(@bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), -1, @bitCast(i128, u128(0x80000000000000000000000000000001)), 0);
47 test__muloti4(-1, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), @bitCast(i128, u128(0x80000000000000000000000000000001)), 0);
48 test__muloti4(@bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0, 0, 0);
49 test__muloti4(0, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0, 0);
50 test__muloti4(@bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 1, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0);
51 test__muloti4(1, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0);
52 test__muloti4(@bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 2, @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
53 test__muloti4(2, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
54
55 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000000)), -2, @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
56 test__muloti4(-2, @bitCast(i128, u128(0x80000000000000000000000000000000)), @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
57 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000000)), -1, @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
58 test__muloti4(-1, @bitCast(i128, u128(0x80000000000000000000000000000000)), @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
59 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000000)), 0, 0, 0);
60 test__muloti4(0, @bitCast(i128, u128(0x80000000000000000000000000000000)), 0, 0);
61 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000000)), 1, @bitCast(i128, u128(0x80000000000000000000000000000000)), 0);
62 test__muloti4(1, @bitCast(i128, u128(0x80000000000000000000000000000000)), @bitCast(i128, u128(0x80000000000000000000000000000000)), 0);
63 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000000)), 2, @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
64 test__muloti4(2, @bitCast(i128, u128(0x80000000000000000000000000000000)), @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
65
66 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000001)), -2, @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
67 test__muloti4(-2, @bitCast(i128, u128(0x80000000000000000000000000000001)), @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
68 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000001)), -1, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0);
69 test__muloti4(-1, @bitCast(i128, u128(0x80000000000000000000000000000001)), @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0);
70 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000001)), 0, 0, 0);
71 test__muloti4(0, @bitCast(i128, u128(0x80000000000000000000000000000001)), 0, 0);
72 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000001)), 1, @bitCast(i128, u128(0x80000000000000000000000000000001)), 0);
73 test__muloti4(1, @bitCast(i128, u128(0x80000000000000000000000000000001)), @bitCast(i128, u128(0x80000000000000000000000000000001)), 0);
74 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000001)), 2, @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
75 test__muloti4(2, @bitCast(i128, u128(0x80000000000000000000000000000001)), @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
76}
std/unicode.zig+13-13
......@@ -220,7 +220,7 @@ const Utf8Iterator = struct {
220220 }
221221
222222 pub fn nextCodepoint(it: *Utf8Iterator) ?u32 {
223 const slice = it.nextCodepointSlice() ?? return null;
223 const slice = it.nextCodepointSlice() orelse return null;
224224
225225 switch (slice.len) {
226226 1 => return u32(slice[0]),
......@@ -286,15 +286,15 @@ fn testUtf8IteratorOnAscii() void {
286286 const s = Utf8View.initComptime("abc");
287287
288288 var it1 = s.iterator();
289 debug.assert(std.mem.eql(u8, "a", ??it1.nextCodepointSlice()));
290 debug.assert(std.mem.eql(u8, "b", ??it1.nextCodepointSlice()));
291 debug.assert(std.mem.eql(u8, "c", ??it1.nextCodepointSlice()));
289 debug.assert(std.mem.eql(u8, "a", it1.nextCodepointSlice().?));
290 debug.assert(std.mem.eql(u8, "b", it1.nextCodepointSlice().?));
291 debug.assert(std.mem.eql(u8, "c", it1.nextCodepointSlice().?));
292292 debug.assert(it1.nextCodepointSlice() == null);
293293
294294 var it2 = s.iterator();
295 debug.assert(??it2.nextCodepoint() == 'a');
296 debug.assert(??it2.nextCodepoint() == 'b');
297 debug.assert(??it2.nextCodepoint() == 'c');
295 debug.assert(it2.nextCodepoint().? == 'a');
296 debug.assert(it2.nextCodepoint().? == 'b');
297 debug.assert(it2.nextCodepoint().? == 'c');
298298 debug.assert(it2.nextCodepoint() == null);
299299}
300300
......@@ -321,15 +321,15 @@ fn testUtf8ViewOk() void {
321321 const s = Utf8View.initComptime("東京市");
322322
323323 var it1 = s.iterator();
324 debug.assert(std.mem.eql(u8, "東", ??it1.nextCodepointSlice()));
325 debug.assert(std.mem.eql(u8, "京", ??it1.nextCodepointSlice()));
326 debug.assert(std.mem.eql(u8, "市", ??it1.nextCodepointSlice()));
324 debug.assert(std.mem.eql(u8, "東", it1.nextCodepointSlice().?));
325 debug.assert(std.mem.eql(u8, "京", it1.nextCodepointSlice().?));
326 debug.assert(std.mem.eql(u8, "市", it1.nextCodepointSlice().?));
327327 debug.assert(it1.nextCodepointSlice() == null);
328328
329329 var it2 = s.iterator();
330 debug.assert(??it2.nextCodepoint() == 0x6771);
331 debug.assert(??it2.nextCodepoint() == 0x4eac);
332 debug.assert(??it2.nextCodepoint() == 0x5e02);
330 debug.assert(it2.nextCodepoint().? == 0x6771);
331 debug.assert(it2.nextCodepoint().? == 0x4eac);
332 debug.assert(it2.nextCodepoint().? == 0x5e02);
333333 debug.assert(it2.nextCodepoint() == null);
334334}
335335
std/zig/ast.zig+32-16
......@@ -734,7 +734,7 @@ pub const Node = struct {
734734 var i = index;
735735
736736 if (self.doc_comments) |comments| {
737 if (i < 1) return *comments.base;
737 if (i < 1) return &comments.base;
738738 i -= 1;
739739 }
740740
......@@ -1243,7 +1243,7 @@ pub const Node = struct {
12431243 i -= 1;
12441244
12451245 if (self.@"else") |@"else"| {
1246 if (i < 1) return *@"else".base;
1246 if (i < 1) return &@"else".base;
12471247 i -= 1;
12481248 }
12491249
......@@ -1296,7 +1296,7 @@ pub const Node = struct {
12961296 i -= 1;
12971297
12981298 if (self.@"else") |@"else"| {
1299 if (i < 1) return *@"else".base;
1299 if (i < 1) return &@"else".base;
13001300 i -= 1;
13011301 }
13021302
......@@ -1347,7 +1347,7 @@ pub const Node = struct {
13471347 i -= 1;
13481348
13491349 if (self.@"else") |@"else"| {
1350 if (i < 1) return *@"else".base;
1350 if (i < 1) return &@"else".base;
13511351 i -= 1;
13521352 }
13531353
......@@ -1417,7 +1417,7 @@ pub const Node = struct {
14171417 Range,
14181418 Sub,
14191419 SubWrap,
1420 UnwrapMaybe,
1420 UnwrapOptional,
14211421 };
14221422
14231423 pub fn iterate(self: *InfixOp, index: usize) ?*Node {
......@@ -1475,7 +1475,7 @@ pub const Node = struct {
14751475 Op.Range,
14761476 Op.Sub,
14771477 Op.SubWrap,
1478 Op.UnwrapMaybe,
1478 Op.UnwrapOptional,
14791479 => {},
14801480 }
14811481
......@@ -1507,14 +1507,13 @@ pub const Node = struct {
15071507 BitNot,
15081508 BoolNot,
15091509 Cancel,
1510 MaybeType,
1510 OptionalType,
15111511 Negation,
15121512 NegationWrap,
15131513 Resume,
15141514 PtrType: PtrInfo,
15151515 SliceType: PtrInfo,
15161516 Try,
1517 UnwrapMaybe,
15181517 };
15191518
15201519 pub const PtrInfo = struct {
......@@ -1537,33 +1536,36 @@ pub const Node = struct {
15371536 var i = index;
15381537
15391538 switch (self.op) {
1539 // TODO https://github.com/ziglang/zig/issues/1107
15401540 Op.SliceType => |addr_of_info| {
15411541 if (addr_of_info.align_info) |align_info| {
15421542 if (i < 1) return align_info.node;
15431543 i -= 1;
15441544 }
15451545 },
1546 Op.AddrOf => |addr_of_info| {
1546
1547 Op.PtrType => |addr_of_info| {
15471548 if (addr_of_info.align_info) |align_info| {
15481549 if (i < 1) return align_info.node;
15491550 i -= 1;
15501551 }
15511552 },
1553
15521554 Op.ArrayType => |size_expr| {
15531555 if (i < 1) return size_expr;
15541556 i -= 1;
15551557 },
1558
1559 Op.AddressOf,
15561560 Op.Await,
15571561 Op.BitNot,
15581562 Op.BoolNot,
15591563 Op.Cancel,
1560 Op.MaybeType,
1564 Op.OptionalType,
15611565 Op.Negation,
15621566 Op.NegationWrap,
15631567 Op.Try,
15641568 Op.Resume,
1565 Op.UnwrapMaybe,
1566 Op.PointerType,
15671569 => {},
15681570 }
15691571
......@@ -1619,6 +1621,7 @@ pub const Node = struct {
16191621 ArrayInitializer: InitList,
16201622 StructInitializer: InitList,
16211623 Deref,
1624 UnwrapOptional,
16221625
16231626 pub const InitList = SegmentedList(*Node, 2);
16241627
......@@ -1667,7 +1670,9 @@ pub const Node = struct {
16671670 if (i < fields.len) return fields.at(i).*;
16681671 i -= fields.len;
16691672 },
1670 Op.Deref => {},
1673 Op.UnwrapOptional,
1674 Op.Deref,
1675 => {},
16711676 }
16721677
16731678 return null;
......@@ -2022,7 +2027,7 @@ pub const Node = struct {
20222027
20232028 switch (self.kind) {
20242029 Kind.Variable => |variable_name| {
2025 if (i < 1) return *variable_name.base;
2030 if (i < 1) return &variable_name.base;
20262031 i -= 1;
20272032 },
20282033 Kind.Return => |return_type| {
......@@ -2092,10 +2097,10 @@ pub const Node = struct {
20922097 pub fn iterate(self: *Asm, index: usize) ?*Node {
20932098 var i = index;
20942099
2095 if (i < self.outputs.len) return *(self.outputs.at(index).*).base;
2100 if (i < self.outputs.len) return &self.outputs.at(index).*.base;
20962101 i -= self.outputs.len;
20972102
2098 if (i < self.inputs.len) return *(self.inputs.at(index).*).base;
2103 if (i < self.inputs.len) return &self.inputs.at(index).*.base;
20992104 i -= self.inputs.len;
21002105
21012106 return null;
......@@ -2205,3 +2210,14 @@ pub const Node = struct {
22052210 }
22062211 };
22072212};
2213
2214test "iterate" {
2215 var root = Node.Root{
2216 .base = Node{ .id = Node.Id.Root },
2217 .doc_comments = null,
2218 .decls = Node.Root.DeclList.init(std.debug.global_allocator),
2219 .eof_token = 0,
2220 };
2221 var base = &root.base;
2222 assert(base.iterate(0) == null);
2223}
std/zig/parse.zig+44-34
......@@ -43,7 +43,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
4343
4444 // skip over line comments at the top of the file
4545 while (true) {
46 const next_tok = tok_it.peek() ?? break;
46 const next_tok = tok_it.peek() orelse break;
4747 if (next_tok.id != Token.Id.LineComment) break;
4848 _ = tok_it.next();
4949 }
......@@ -197,7 +197,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
197197 const lib_name_token = nextToken(&tok_it, &tree);
198198 const lib_name_token_index = lib_name_token.index;
199199 const lib_name_token_ptr = lib_name_token.ptr;
200 break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index, &tree)) ?? {
200 break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index, &tree)) orelse {
201201 prevToken(&tok_it, &tree);
202202 break :blk null;
203203 };
......@@ -711,7 +711,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
711711 else => {
712712 // TODO: this is a special case. Remove this when #760 is fixed
713713 if (token_ptr.id == Token.Id.Keyword_error) {
714 if ((??tok_it.peek()).id == Token.Id.LBrace) {
714 if (tok_it.peek().?.id == Token.Id.LBrace) {
715715 const error_type_node = try arena.construct(ast.Node.ErrorType{
716716 .base = ast.Node{ .id = ast.Node.Id.ErrorType },
717717 .token = token_index,
......@@ -1434,14 +1434,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
14341434 try stack.append(State{
14351435 .ExpectTokenSave = ExpectTokenSave{
14361436 .id = Token.Id.AngleBracketRight,
1437 .ptr = &??async_node.rangle_bracket,
1437 .ptr = &async_node.rangle_bracket.?,
14381438 },
14391439 });
14401440 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .RequiredNull = &async_node.allocator_type } });
14411441 continue;
14421442 },
14431443 State.AsyncEnd => |ctx| {
1444 const node = ctx.ctx.get() ?? continue;
1444 const node = ctx.ctx.get() orelse continue;
14451445
14461446 switch (node.id) {
14471447 ast.Node.Id.FnProto => {
......@@ -1567,7 +1567,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
15671567 .bit_range = null,
15681568 };
15691569 // TODO https://github.com/ziglang/zig/issues/1022
1570 const align_info = &??addr_of_info.align_info;
1570 const align_info = &addr_of_info.align_info.?;
15711571
15721572 try stack.append(State{ .AlignBitRange = align_info });
15731573 try stack.append(State{ .Expression = OptionalCtx{ .Required = &align_info.node } });
......@@ -1604,7 +1604,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
16041604 switch (token.ptr.id) {
16051605 Token.Id.Colon => {
16061606 align_info.bit_range = ast.Node.PrefixOp.PtrInfo.Align.BitRange(undefined);
1607 const bit_range = &??align_info.bit_range;
1607 const bit_range = &align_info.bit_range.?;
16081608
16091609 try stack.append(State{ .ExpectToken = Token.Id.RParen });
16101610 try stack.append(State{ .Expression = OptionalCtx{ .Required = &bit_range.end } });
......@@ -1814,7 +1814,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
18141814 continue;
18151815 },
18161816 State.RangeExpressionEnd => |opt_ctx| {
1817 const lhs = opt_ctx.get() ?? continue;
1817 const lhs = opt_ctx.get() orelse continue;
18181818
18191819 if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {
18201820 const node = try arena.construct(ast.Node.InfixOp{
......@@ -1836,7 +1836,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
18361836 },
18371837
18381838 State.AssignmentExpressionEnd => |opt_ctx| {
1839 const lhs = opt_ctx.get() ?? continue;
1839 const lhs = opt_ctx.get() orelse continue;
18401840
18411841 const token = nextToken(&tok_it, &tree);
18421842 const token_index = token.index;
......@@ -1866,7 +1866,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
18661866 },
18671867
18681868 State.UnwrapExpressionEnd => |opt_ctx| {
1869 const lhs = opt_ctx.get() ?? continue;
1869 const lhs = opt_ctx.get() orelse continue;
18701870
18711871 const token = nextToken(&tok_it, &tree);
18721872 const token_index = token.index;
......@@ -1901,7 +1901,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
19011901 },
19021902
19031903 State.BoolOrExpressionEnd => |opt_ctx| {
1904 const lhs = opt_ctx.get() ?? continue;
1904 const lhs = opt_ctx.get() orelse continue;
19051905
19061906 if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| {
19071907 const node = try arena.construct(ast.Node.InfixOp{
......@@ -1925,7 +1925,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
19251925 },
19261926
19271927 State.BoolAndExpressionEnd => |opt_ctx| {
1928 const lhs = opt_ctx.get() ?? continue;
1928 const lhs = opt_ctx.get() orelse continue;
19291929
19301930 if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| {
19311931 const node = try arena.construct(ast.Node.InfixOp{
......@@ -1949,7 +1949,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
19491949 },
19501950
19511951 State.ComparisonExpressionEnd => |opt_ctx| {
1952 const lhs = opt_ctx.get() ?? continue;
1952 const lhs = opt_ctx.get() orelse continue;
19531953
19541954 const token = nextToken(&tok_it, &tree);
19551955 const token_index = token.index;
......@@ -1979,7 +1979,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
19791979 },
19801980
19811981 State.BinaryOrExpressionEnd => |opt_ctx| {
1982 const lhs = opt_ctx.get() ?? continue;
1982 const lhs = opt_ctx.get() orelse continue;
19831983
19841984 if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| {
19851985 const node = try arena.construct(ast.Node.InfixOp{
......@@ -2003,7 +2003,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
20032003 },
20042004
20052005 State.BinaryXorExpressionEnd => |opt_ctx| {
2006 const lhs = opt_ctx.get() ?? continue;
2006 const lhs = opt_ctx.get() orelse continue;
20072007
20082008 if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| {
20092009 const node = try arena.construct(ast.Node.InfixOp{
......@@ -2027,7 +2027,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
20272027 },
20282028
20292029 State.BinaryAndExpressionEnd => |opt_ctx| {
2030 const lhs = opt_ctx.get() ?? continue;
2030 const lhs = opt_ctx.get() orelse continue;
20312031
20322032 if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| {
20332033 const node = try arena.construct(ast.Node.InfixOp{
......@@ -2051,7 +2051,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
20512051 },
20522052
20532053 State.BitShiftExpressionEnd => |opt_ctx| {
2054 const lhs = opt_ctx.get() ?? continue;
2054 const lhs = opt_ctx.get() orelse continue;
20552055
20562056 const token = nextToken(&tok_it, &tree);
20572057 const token_index = token.index;
......@@ -2081,7 +2081,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
20812081 },
20822082
20832083 State.AdditionExpressionEnd => |opt_ctx| {
2084 const lhs = opt_ctx.get() ?? continue;
2084 const lhs = opt_ctx.get() orelse continue;
20852085
20862086 const token = nextToken(&tok_it, &tree);
20872087 const token_index = token.index;
......@@ -2111,7 +2111,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
21112111 },
21122112
21132113 State.MultiplyExpressionEnd => |opt_ctx| {
2114 const lhs = opt_ctx.get() ?? continue;
2114 const lhs = opt_ctx.get() orelse continue;
21152115
21162116 const token = nextToken(&tok_it, &tree);
21172117 const token_index = token.index;
......@@ -2142,9 +2142,9 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
21422142 },
21432143
21442144 State.CurlySuffixExpressionEnd => |opt_ctx| {
2145 const lhs = opt_ctx.get() ?? continue;
2145 const lhs = opt_ctx.get() orelse continue;
21462146
2147 if ((??tok_it.peek()).id == Token.Id.Period) {
2147 if (tok_it.peek().?.id == Token.Id.Period) {
21482148 const node = try arena.construct(ast.Node.SuffixOp{
21492149 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
21502150 .lhs = lhs,
......@@ -2190,7 +2190,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
21902190 },
21912191
21922192 State.TypeExprEnd => |opt_ctx| {
2193 const lhs = opt_ctx.get() ?? continue;
2193 const lhs = opt_ctx.get() orelse continue;
21942194
21952195 if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| {
21962196 const node = try arena.construct(ast.Node.InfixOp{
......@@ -2270,7 +2270,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
22702270 },
22712271
22722272 State.SuffixOpExpressionEnd => |opt_ctx| {
2273 const lhs = opt_ctx.get() ?? continue;
2273 const lhs = opt_ctx.get() orelse continue;
22742274
22752275 const token = nextToken(&tok_it, &tree);
22762276 const token_index = token.index;
......@@ -2326,6 +2326,17 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
23262326 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
23272327 continue;
23282328 }
2329 if (eatToken(&tok_it, &tree, Token.Id.QuestionMark)) |question_token| {
2330 const node = try arena.construct(ast.Node.SuffixOp{
2331 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2332 .lhs = lhs,
2333 .op = ast.Node.SuffixOp.Op.UnwrapOptional,
2334 .rtoken = question_token,
2335 });
2336 opt_ctx.store(&node.base);
2337 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2338 continue;
2339 }
23292340 const node = try arena.construct(ast.Node.InfixOp{
23302341 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
23312342 .lhs = lhs,
......@@ -2403,12 +2414,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
24032414 .arrow_token = next_token_index,
24042415 .return_type = undefined,
24052416 };
2406 const return_type_ptr = &((??node.result).return_type);
2417 const return_type_ptr = &node.result.?.return_type;
24072418 try stack.append(State{ .Expression = OptionalCtx{ .Required = return_type_ptr } });
24082419 continue;
24092420 },
24102421 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
2411 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token.ptr, token.index, &tree)) ?? unreachable);
2422 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token.ptr, token.index, &tree)) orelse unreachable);
24122423 continue;
24132424 },
24142425 Token.Id.LParen => {
......@@ -2638,7 +2649,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
26382649 const token = nextToken(&tok_it, &tree);
26392650 const token_index = token.index;
26402651 const token_ptr = token.ptr;
2641 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token_ptr, token_index, &tree)) ?? {
2652 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token_ptr, token_index, &tree)) orelse {
26422653 prevToken(&tok_it, &tree);
26432654 if (opt_ctx != OptionalCtx.Optional) {
26442655 ((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token_index } };
......@@ -2875,7 +2886,7 @@ const OptionalCtx = union(enum) {
28752886 pub fn get(self: *const OptionalCtx) ?*ast.Node {
28762887 switch (self.*) {
28772888 OptionalCtx.Optional => |ptr| return ptr.*,
2878 OptionalCtx.RequiredNull => |ptr| return ??ptr.*,
2889 OptionalCtx.RequiredNull => |ptr| return ptr.*.?,
28792890 OptionalCtx.Required => |ptr| return ptr.*,
28802891 }
28812892 }
......@@ -3237,7 +3248,7 @@ fn tokenIdToAssignment(id: *const Token.Id) ?ast.Node.InfixOp.Op {
32373248fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
32383249 return switch (id) {
32393250 Token.Id.Keyword_catch => ast.Node.InfixOp.Op{ .Catch = null },
3240 Token.Id.QuestionMarkQuestionMark => ast.Node.InfixOp.Op{ .UnwrapMaybe = void{} },
3251 Token.Id.Keyword_orelse => ast.Node.InfixOp.Op{ .UnwrapOptional = void{} },
32413252 else => null,
32423253 };
32433254}
......@@ -3299,8 +3310,7 @@ fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {
32993310 .volatile_token = null,
33003311 },
33013312 },
3302 Token.Id.QuestionMark => ast.Node.PrefixOp.Op{ .MaybeType = void{} },
3303 Token.Id.QuestionMarkQuestionMark => ast.Node.PrefixOp.Op{ .UnwrapMaybe = void{} },
3313 Token.Id.QuestionMark => ast.Node.PrefixOp.Op{ .OptionalType = void{} },
33043314 Token.Id.Keyword_await => ast.Node.PrefixOp.Op{ .Await = void{} },
33053315 Token.Id.Keyword_try => ast.Node.PrefixOp.Op{ .Try = void{} },
33063316 else => null,
......@@ -3322,7 +3332,7 @@ fn createToCtxLiteral(arena: *mem.Allocator, opt_ctx: *const OptionalCtx, compti
33223332}
33233333
33243334fn eatToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree, id: @TagType(Token.Id)) ?TokenIndex {
3325 const token = ??tok_it.peek();
3335 const token = tok_it.peek().?;
33263336
33273337 if (token.id == id) {
33283338 return nextToken(tok_it, tree).index;
......@@ -3334,12 +3344,12 @@ fn eatToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree, id: @TagType(
33343344fn nextToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree) AnnotatedToken {
33353345 const result = AnnotatedToken{
33363346 .index = tok_it.index,
3337 .ptr = ??tok_it.next(),
3347 .ptr = tok_it.next().?,
33383348 };
33393349 assert(result.ptr.id != Token.Id.LineComment);
33403350
33413351 while (true) {
3342 const next_tok = tok_it.peek() ?? return result;
3352 const next_tok = tok_it.peek() orelse return result;
33433353 if (next_tok.id != Token.Id.LineComment) return result;
33443354 _ = tok_it.next();
33453355 }
......@@ -3347,7 +3357,7 @@ fn nextToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree) AnnotatedTok
33473357
33483358fn prevToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree) void {
33493359 while (true) {
3350 const prev_tok = tok_it.prev() ?? return;
3360 const prev_tok = tok_it.prev() orelse return;
33513361 if (prev_tok.id == Token.Id.LineComment) continue;
33523362 return;
33533363 }
std/zig/parser_test.zig+4-3
......@@ -650,9 +650,10 @@ test "zig fmt: statements with empty line between" {
650650 );
651651}
652652
653test "zig fmt: ptr deref operator" {
653test "zig fmt: ptr deref operator and unwrap optional operator" {
654654 try testCanonical(
655655 \\const a = b.*;
656 \\const a = b.?;
656657 \\
657658 );
658659}
......@@ -1150,7 +1151,7 @@ test "zig fmt: infix operators" {
11501151 \\ _ = i!i;
11511152 \\ _ = i ** i;
11521153 \\ _ = i ++ i;
1153 \\ _ = i ?? i;
1154 \\ _ = i orelse i;
11541155 \\ _ = i % i;
11551156 \\ _ = i / i;
11561157 \\ _ = i *% i;
......@@ -1209,7 +1210,7 @@ test "zig fmt: precedence" {
12091210test "zig fmt: prefix operators" {
12101211 try testCanonical(
12111212 \\test "prefix operators" {
1212 \\ try return --%~??!*&0;
1213 \\ try return --%~!*&0;
12131214 \\}
12141215 \\
12151216 );
std/zig/render.zig+16-17
......@@ -83,7 +83,7 @@ fn renderRoot(
8383 var start_col: usize = 0;
8484 var it = tree.root_node.decls.iterator(0);
8585 while (true) {
86 var decl = (it.next() ?? return).*;
86 var decl = (it.next() orelse return).*;
8787 // look for zig fmt: off comment
8888 var start_token_index = decl.firstToken();
8989 zig_fmt_loop: while (start_token_index != 0) {
......@@ -112,7 +112,7 @@ fn renderRoot(
112112 const start = tree.tokens.at(start_token_index + 1).start;
113113 try stream.print("{}\n", tree.source[start..end_token.end]);
114114 while (tree.tokens.at(decl.firstToken()).start < end_token.end) {
115 decl = (it.next() ?? return).*;
115 decl = (it.next() orelse return).*;
116116 }
117117 break :zig_fmt_loop;
118118 }
......@@ -222,7 +222,7 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i
222222 }
223223 }
224224
225 const value_expr = ??tag.value_expr;
225 const value_expr = tag.value_expr.?;
226226 try renderToken(tree, stream, tree.prevToken(value_expr.firstToken()), indent, start_col, Space.Space); // =
227227 try renderExpression(allocator, stream, tree, indent, start_col, value_expr, Space.Comma); // value,
228228 },
......@@ -465,8 +465,7 @@ fn renderExpression(
465465 ast.Node.PrefixOp.Op.BoolNot,
466466 ast.Node.PrefixOp.Op.Negation,
467467 ast.Node.PrefixOp.Op.NegationWrap,
468 ast.Node.PrefixOp.Op.UnwrapMaybe,
469 ast.Node.PrefixOp.Op.MaybeType,
468 ast.Node.PrefixOp.Op.OptionalType,
470469 ast.Node.PrefixOp.Op.AddressOf,
471470 => {
472471 try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None);
......@@ -513,7 +512,7 @@ fn renderExpression(
513512
514513 var it = call_info.params.iterator(0);
515514 while (true) {
516 const param_node = ??it.next();
515 const param_node = it.next().?;
517516
518517 const param_node_new_indent = if (param_node.*.id == ast.Node.Id.MultilineStringLiteral) blk: {
519518 break :blk indent;
......@@ -559,10 +558,10 @@ fn renderExpression(
559558 return renderToken(tree, stream, rbracket, indent, start_col, space); // ]
560559 },
561560
562 ast.Node.SuffixOp.Op.Deref => {
561 ast.Node.SuffixOp.Op.Deref, ast.Node.SuffixOp.Op.UnwrapOptional => {
563562 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
564563 try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // .
565 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // *
564 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // * or ?
566565 },
567566
568567 @TagType(ast.Node.SuffixOp.Op).Slice => |range| {
......@@ -595,7 +594,7 @@ fn renderExpression(
595594 }
596595
597596 if (field_inits.len == 1) blk: {
598 const field_init = ??field_inits.at(0).*.cast(ast.Node.FieldInitializer);
597 const field_init = field_inits.at(0).*.cast(ast.Node.FieldInitializer).?;
599598
600599 if (field_init.expr.cast(ast.Node.SuffixOp)) |nested_suffix_op| {
601600 if (nested_suffix_op.op == ast.Node.SuffixOp.Op.StructInitializer) {
......@@ -688,7 +687,7 @@ fn renderExpression(
688687 var count: usize = 1;
689688 var it = exprs.iterator(0);
690689 while (true) {
691 const expr = (??it.next()).*;
690 const expr = it.next().?.*;
692691 if (it.peek()) |next_expr| {
693692 const expr_last_token = expr.*.lastToken() + 1;
694693 const loc = tree.tokenLocation(tree.tokens.at(expr_last_token).end, next_expr.*.firstToken());
......@@ -806,7 +805,7 @@ fn renderExpression(
806805 },
807806 }
808807
809 return renderExpression(allocator, stream, tree, indent, start_col, ??flow_expr.rhs, space);
808 return renderExpression(allocator, stream, tree, indent, start_col, flow_expr.rhs.?, space);
810809 },
811810
812811 ast.Node.Id.Payload => {
......@@ -1245,7 +1244,7 @@ fn renderExpression(
12451244 } else {
12461245 var it = switch_case.items.iterator(0);
12471246 while (true) {
1248 const node = ??it.next();
1247 const node = it.next().?;
12491248 if (it.peek()) |next_node| {
12501249 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None);
12511250
......@@ -1550,7 +1549,7 @@ fn renderExpression(
15501549
15511550 var it = asm_node.outputs.iterator(0);
15521551 while (true) {
1553 const asm_output = ??it.next();
1552 const asm_output = it.next().?;
15541553 const node = &(asm_output.*).base;
15551554
15561555 if (it.peek()) |next_asm_output| {
......@@ -1588,7 +1587,7 @@ fn renderExpression(
15881587
15891588 var it = asm_node.inputs.iterator(0);
15901589 while (true) {
1591 const asm_input = ??it.next();
1590 const asm_input = it.next().?;
15921591 const node = &(asm_input.*).base;
15931592
15941593 if (it.peek()) |next_asm_input| {
......@@ -1620,7 +1619,7 @@ fn renderExpression(
16201619
16211620 var it = asm_node.clobbers.iterator(0);
16221621 while (true) {
1623 const clobber_token = ??it.next();
1622 const clobber_token = it.next().?;
16241623
16251624 if (it.peek() == null) {
16261625 try renderToken(tree, stream, clobber_token.*, indent_once, start_col, Space.Newline);
......@@ -1994,7 +1993,7 @@ fn renderDocComments(
19941993 indent: usize,
19951994 start_col: *usize,
19961995) (@typeOf(stream).Child.Error || Error)!void {
1997 const comment = node.doc_comments ?? return;
1996 const comment = node.doc_comments orelse return;
19981997 var it = comment.lines.iterator(0);
19991998 const first_token = node.firstToken();
20001999 while (it.next()) |line_token_index| {
......@@ -2022,7 +2021,7 @@ fn nodeIsBlock(base: *const ast.Node) bool {
20222021}
20232022
20242023fn nodeCausesSliceOpSpace(base: *ast.Node) bool {
2025 const infix_op = base.cast(ast.Node.InfixOp) ?? return false;
2024 const infix_op = base.cast(ast.Node.InfixOp) orelse return false;
20262025 return switch (infix_op.op) {
20272026 ast.Node.InfixOp.Op.Period => false,
20282027 else => true,
std/zig/tokenizer.zig+7-20
......@@ -39,6 +39,7 @@ pub const Token = struct {
3939 Keyword{ .bytes = "noalias", .id = Id.Keyword_noalias },
4040 Keyword{ .bytes = "null", .id = Id.Keyword_null },
4141 Keyword{ .bytes = "or", .id = Id.Keyword_or },
42 Keyword{ .bytes = "orelse", .id = Id.Keyword_orelse },
4243 Keyword{ .bytes = "packed", .id = Id.Keyword_packed },
4344 Keyword{ .bytes = "promise", .id = Id.Keyword_promise },
4445 Keyword{ .bytes = "pub", .id = Id.Keyword_pub },
......@@ -129,7 +130,6 @@ pub const Token = struct {
129130 Ampersand,
130131 AmpersandEqual,
131132 QuestionMark,
132 QuestionMarkQuestionMark,
133133 AngleBracketLeft,
134134 AngleBracketLeftEqual,
135135 AngleBracketAngleBracketLeft,
......@@ -171,6 +171,7 @@ pub const Token = struct {
171171 Keyword_noalias,
172172 Keyword_null,
173173 Keyword_or,
174 Keyword_orelse,
174175 Keyword_packed,
175176 Keyword_promise,
176177 Keyword_pub,
......@@ -254,7 +255,6 @@ pub const Tokenizer = struct {
254255 Ampersand,
255256 Caret,
256257 Percent,
257 QuestionMark,
258258 Plus,
259259 PlusPercent,
260260 AngleBracketLeft,
......@@ -345,6 +345,11 @@ pub const Tokenizer = struct {
345345 self.index += 1;
346346 break;
347347 },
348 '?' => {
349 result.id = Token.Id.QuestionMark;
350 self.index += 1;
351 break;
352 },
348353 ':' => {
349354 result.id = Token.Id.Colon;
350355 self.index += 1;
......@@ -359,9 +364,6 @@ pub const Tokenizer = struct {
359364 '+' => {
360365 state = State.Plus;
361366 },
362 '?' => {
363 state = State.QuestionMark;
364 },
365367 '<' => {
366368 state = State.AngleBracketLeft;
367369 },
......@@ -496,18 +498,6 @@ pub const Tokenizer = struct {
496498 },
497499 },
498500
499 State.QuestionMark => switch (c) {
500 '?' => {
501 result.id = Token.Id.QuestionMarkQuestionMark;
502 self.index += 1;
503 break;
504 },
505 else => {
506 result.id = Token.Id.QuestionMark;
507 break;
508 },
509 },
510
511501 State.Percent => switch (c) {
512502 '=' => {
513503 result.id = Token.Id.PercentEqual;
......@@ -1084,9 +1074,6 @@ pub const Tokenizer = struct {
10841074 State.Plus => {
10851075 result.id = Token.Id.Plus;
10861076 },
1087 State.QuestionMark => {
1088 result.id = Token.Id.QuestionMark;
1089 },
10901077 State.Percent => {
10911078 result.id = Token.Id.Percent;
10921079 },
test/behavior.zig+1
......@@ -31,6 +31,7 @@ comptime {
3131 _ = @import("cases/incomplete_struct_param_tld.zig");
3232 _ = @import("cases/ir_block_deps.zig");
3333 _ = @import("cases/math.zig");
34 _ = @import("cases/merge_error_sets.zig");
3435 _ = @import("cases/misc.zig");
3536 _ = @import("cases/namespace_depends_on_compile_var/index.zig");
3637 _ = @import("cases/new_stack_call.zig");
test/cases/array.zig+9-1
......@@ -116,6 +116,15 @@ test "array len property" {
116116 assert(@typeOf(x).len == 5);
117117}
118118
119test "array len field" {
120 var arr = [4]u8{ 0, 0, 0, 0 };
121 var ptr = &arr;
122 assert(arr.len == 4);
123 comptime assert(arr.len == 4);
124 assert(ptr.len == 4);
125 comptime assert(ptr.len == 4);
126}
127
119128test "single-item pointer to array indexing and slicing" {
120129 testSingleItemPtrArrayIndexSlice();
121130 comptime testSingleItemPtrArrayIndexSlice();
......@@ -143,4 +152,3 @@ fn testImplicitCastSingleItemPtr() void {
143152 slice[0] += 1;
144153 assert(byte == 101);
145154}
146
test/cases/bugs/656.zig+1-1
......@@ -9,7 +9,7 @@ const Value = struct {
99 align_expr: ?u32,
1010};
1111
12test "nullable if after an if in a switch prong of a switch with 2 prongs in an else" {
12test "optional if after an if in a switch prong of a switch with 2 prongs in an else" {
1313 foo(false, true);
1414}
1515
test/cases/cast.zig+51-29
......@@ -1,5 +1,6 @@
1const assert = @import("std").debug.assert;
2const mem = @import("std").mem;
1const std = @import("std");
2const assert = std.debug.assert;
3const mem = std.mem;
34
45test "int to ptr cast" {
56 const x = usize(13);
......@@ -72,7 +73,7 @@ fn Struct(comptime T: type) type {
7273
7374 fn maybePointer(self: ?*const Self) Self {
7475 const none = Self{ .x = if (T == void) void{} else 0 };
75 return (self ?? &none).*;
76 return (self orelse &none).*;
7677 }
7778 };
7879}
......@@ -86,7 +87,7 @@ const Union = union {
8687
8788 fn maybePointer(self: ?*const Union) Union {
8889 const none = Union{ .x = 0 };
89 return (self ?? &none).*;
90 return (self orelse &none).*;
9091 }
9192};
9293
......@@ -99,7 +100,7 @@ const Enum = enum {
99100 }
100101
101102 fn maybePointer(self: ?*const Enum) Enum {
102 return (self ?? &Enum.None).*;
103 return (self orelse &Enum.None).*;
103104 }
104105};
105106
......@@ -108,16 +109,16 @@ test "implicitly cast indirect pointer to maybe-indirect pointer" {
108109 const Self = this;
109110 x: u8,
110111 fn constConst(p: *const *const Self) u8 {
111 return (p.*).x;
112 return p.*.x;
112113 }
113114 fn maybeConstConst(p: ?*const *const Self) u8 {
114 return ((??p).*).x;
115 return p.?.*.x;
115116 }
116117 fn constConstConst(p: *const *const *const Self) u8 {
117 return (p.*.*).x;
118 return p.*.*.x;
118119 }
119120 fn maybeConstConstConst(p: ?*const *const *const Self) u8 {
120 return ((??p).*.*).x;
121 return p.?.*.*.x;
121122 }
122123 };
123124 const s = S{ .x = 42 };
......@@ -176,56 +177,56 @@ test "string literal to &const []const u8" {
176177}
177178
178179test "implicitly cast from T to error!?T" {
179 castToMaybeTypeError(1);
180 comptime castToMaybeTypeError(1);
180 castToOptionalTypeError(1);
181 comptime castToOptionalTypeError(1);
181182}
182183const A = struct {
183184 a: i32,
184185};
185fn castToMaybeTypeError(z: i32) void {
186fn castToOptionalTypeError(z: i32) void {
186187 const x = i32(1);
187188 const y: error!?i32 = x;
188 assert(??(try y) == 1);
189 assert((try y).? == 1);
189190
190191 const f = z;
191192 const g: error!?i32 = f;
192193
193194 const a = A{ .a = z };
194195 const b: error!?A = a;
195 assert((??(b catch unreachable)).a == 1);
196 assert((b catch unreachable).?.a == 1);
196197}
197198
198199test "implicitly cast from int to error!?T" {
199 implicitIntLitToMaybe();
200 comptime implicitIntLitToMaybe();
200 implicitIntLitToOptional();
201 comptime implicitIntLitToOptional();
201202}
202fn implicitIntLitToMaybe() void {
203fn implicitIntLitToOptional() void {
203204 const f: ?i32 = 1;
204205 const g: error!?i32 = 1;
205206}
206207
207208test "return null from fn() error!?&T" {
208 const a = returnNullFromMaybeTypeErrorRef();
209 const b = returnNullLitFromMaybeTypeErrorRef();
209 const a = returnNullFromOptionalTypeErrorRef();
210 const b = returnNullLitFromOptionalTypeErrorRef();
210211 assert((try a) == null and (try b) == null);
211212}
212fn returnNullFromMaybeTypeErrorRef() error!?*A {
213fn returnNullFromOptionalTypeErrorRef() error!?*A {
213214 const a: ?*A = null;
214215 return a;
215216}
216fn returnNullLitFromMaybeTypeErrorRef() error!?*A {
217fn returnNullLitFromOptionalTypeErrorRef() error!?*A {
217218 return null;
218219}
219220
220221test "peer type resolution: ?T and T" {
221 assert(??peerTypeTAndMaybeT(true, false) == 0);
222 assert(??peerTypeTAndMaybeT(false, false) == 3);
222 assert(peerTypeTAndOptionalT(true, false).? == 0);
223 assert(peerTypeTAndOptionalT(false, false).? == 3);
223224 comptime {
224 assert(??peerTypeTAndMaybeT(true, false) == 0);
225 assert(??peerTypeTAndMaybeT(false, false) == 3);
225 assert(peerTypeTAndOptionalT(true, false).? == 0);
226 assert(peerTypeTAndOptionalT(false, false).? == 3);
226227 }
227228}
228fn peerTypeTAndMaybeT(c: bool, b: bool) ?usize {
229fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
229230 if (c) {
230231 return if (b) null else usize(0);
231232 }
......@@ -250,11 +251,11 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
250251}
251252
252253test "implicitly cast from [N]T to ?[]const T" {
253 assert(mem.eql(u8, ??castToMaybeSlice(), "hi"));
254 comptime assert(mem.eql(u8, ??castToMaybeSlice(), "hi"));
254 assert(mem.eql(u8, castToOptionalSlice().?, "hi"));
255 comptime assert(mem.eql(u8, castToOptionalSlice().?, "hi"));
255256}
256257
257fn castToMaybeSlice() ?[]const u8 {
258fn castToOptionalSlice() ?[]const u8 {
258259 return "hi";
259260}
260261
......@@ -384,3 +385,24 @@ test "const slice widen cast" {
384385
385386 assert(@bitCast(u32, bytes) == 0x12121212);
386387}
388
389test "single-item pointer of array to slice and to unknown length pointer" {
390 testCastPtrOfArrayToSliceAndPtr();
391 comptime testCastPtrOfArrayToSliceAndPtr();
392}
393
394fn testCastPtrOfArrayToSliceAndPtr() void {
395 var array = "ao" ++ "eu"; // TODO https://github.com/ziglang/zig/issues/1076
396 const x: [*]u8 = &array;
397 x[0] += 1;
398 assert(mem.eql(u8, array[0..], "boeu"));
399 const y: []u8 = &array;
400 y[0] += 1;
401 assert(mem.eql(u8, array[0..], "coeu"));
402}
403
404test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
405 const window_name = [1][*]const u8{c"window name"};
406 const x: [*]const ?[*]const u8 = &window_name;
407 assert(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name"));
408}
test/cases/enum.zig+9
......@@ -883,3 +883,12 @@ test "empty extern enum with members" {
883883 };
884884 assert(@sizeOf(E) == @sizeOf(c_int));
885885}
886
887test "aoeu" {
888 const LocalFoo = enum {
889 A = 1,
890 B = 0,
891 };
892 var b = LocalFoo.B;
893 assert(mem.eql(u8, @tagName(b), "B"));
894}
test/cases/error.zig+1-1
......@@ -140,7 +140,7 @@ fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void {
140140 if (x) |v| assert(v == 1234) else |err| @compileError("bad");
141141}
142142
143test "syntax: nullable operator in front of error union operator" {
143test "syntax: optional operator in front of error union operator" {
144144 comptime {
145145 assert(?error!i32 == ?(error!i32));
146146 }
test/cases/eval.zig+14-1
......@@ -12,7 +12,7 @@ fn fibonacci(x: i32) i32 {
1212}
1313
1414fn unwrapAndAddOne(blah: ?i32) i32 {
15 return ??blah + 1;
15 return blah.? + 1;
1616}
1717const should_be_1235 = unwrapAndAddOne(1234);
1818test "static add one" {
......@@ -610,3 +610,16 @@ test "slice of type" {
610610 }
611611 }
612612}
613
614const Wrapper = struct {
615 T: type,
616};
617
618fn wrap(comptime T: type) Wrapper {
619 return Wrapper{ .T = T };
620}
621
622test "function which returns struct with type field causes implicit comptime" {
623 const ty = wrap(i32).T;
624 assert(ty == i32);
625}
test/cases/generics.zig+1-1
......@@ -127,7 +127,7 @@ test "generic fn with implicit cast" {
127127 }) == 0);
128128}
129129fn getByte(ptr: ?*const u8) u8 {
130 return (??ptr).*;
130 return ptr.?.*;
131131}
132132fn getFirstByte(comptime T: type, mem: []const T) u8 {
133133 return getByte(@ptrCast(*const u8, &mem[0]));
test/cases/merge_error_sets.zig created+21
......@@ -0,0 +1,21 @@
1const A = error{
2 PathNotFound,
3 NotDir,
4};
5const B = error{OutOfMemory};
6
7const C = A || B;
8
9fn foo() C!void {
10 return error.NotDir;
11}
12
13test "merge error sets" {
14 if (foo()) {
15 @panic("unexpected");
16 } else |err| switch (err) {
17 error.OutOfMemory => @panic("unexpected"),
18 error.PathNotFound => @panic("unexpected"),
19 error.NotDir => {},
20 }
21}
test/cases/misc.zig+1-9
......@@ -505,7 +505,7 @@ test "@typeId" {
505505 assert(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat);
506506 assert(@typeId(@typeOf(undefined)) == Tid.Undefined);
507507 assert(@typeId(@typeOf(null)) == Tid.Null);
508 assert(@typeId(?i32) == Tid.Nullable);
508 assert(@typeId(?i32) == Tid.Optional);
509509 assert(@typeId(error!i32) == Tid.ErrorUnion);
510510 assert(@typeId(error) == Tid.ErrorSet);
511511 assert(@typeId(AnEnum) == Tid.Enum);
......@@ -523,14 +523,6 @@ test "@typeId" {
523523 }
524524}
525525
526test "@canImplicitCast" {
527 comptime {
528 assert(@canImplicitCast(i64, i32(3)));
529 assert(!@canImplicitCast(i32, f32(1.234)));
530 assert(@canImplicitCast([]const u8, "aoeu"));
531 }
532}
533
534526test "@typeName" {
535527 const Struct = struct {};
536528 const Union = union {
test/cases/null.zig+31-20
......@@ -1,6 +1,6 @@
11const assert = @import("std").debug.assert;
22
3test "nullable type" {
3test "optional type" {
44 const x: ?bool = true;
55
66 if (x) |y| {
......@@ -15,13 +15,13 @@ test "nullable type" {
1515
1616 const next_x: ?i32 = null;
1717
18 const z = next_x ?? 1234;
18 const z = next_x orelse 1234;
1919
2020 assert(z == 1234);
2121
2222 const final_x: ?i32 = 13;
2323
24 const num = final_x ?? unreachable;
24 const num = final_x orelse unreachable;
2525
2626 assert(num == 13);
2727}
......@@ -33,12 +33,12 @@ test "test maybe object and get a pointer to the inner value" {
3333 b.* = false;
3434 }
3535
36 assert(??maybe_bool == false);
36 assert(maybe_bool.? == false);
3737}
3838
3939test "rhs maybe unwrap return" {
4040 const x: ?bool = true;
41 const y = x ?? return;
41 const y = x orelse return;
4242}
4343
4444test "maybe return" {
......@@ -47,13 +47,13 @@ test "maybe return" {
4747}
4848
4949fn maybeReturnImpl() void {
50 assert(??foo(1235));
50 assert(foo(1235).?);
5151 if (foo(null) != null) unreachable;
52 assert(!??foo(1234));
52 assert(!foo(1234).?);
5353}
5454
5555fn foo(x: ?i32) ?bool {
56 const value = x ?? return null;
56 const value = x orelse return null;
5757 return value > 1234;
5858}
5959
......@@ -102,12 +102,12 @@ fn testTestNullRuntime(x: ?i32) void {
102102 assert(!(x != null));
103103}
104104
105test "nullable void" {
106 nullableVoidImpl();
107 comptime nullableVoidImpl();
105test "optional void" {
106 optionalVoidImpl();
107 comptime optionalVoidImpl();
108108}
109109
110fn nullableVoidImpl() void {
110fn optionalVoidImpl() void {
111111 assert(bar(null) == null);
112112 assert(bar({}) != null);
113113}
......@@ -120,19 +120,19 @@ fn bar(x: ?void) ?void {
120120 }
121121}
122122
123const StructWithNullable = struct {
123const StructWithOptional = struct {
124124 field: ?i32,
125125};
126126
127var struct_with_nullable: StructWithNullable = undefined;
127var struct_with_optional: StructWithOptional = undefined;
128128
129test "unwrap nullable which is field of global var" {
130 struct_with_nullable.field = null;
131 if (struct_with_nullable.field) |payload| {
129test "unwrap optional which is field of global var" {
130 struct_with_optional.field = null;
131 if (struct_with_optional.field) |payload| {
132132 unreachable;
133133 }
134 struct_with_nullable.field = 1234;
135 if (struct_with_nullable.field) |payload| {
134 struct_with_optional.field = 1234;
135 if (struct_with_optional.field) |payload| {
136136 assert(payload == 1234);
137137 } else {
138138 unreachable;
......@@ -140,6 +140,17 @@ test "unwrap nullable which is field of global var" {
140140}
141141
142142test "null with default unwrap" {
143 const x: i32 = null ?? 1;
143 const x: i32 = null orelse 1;
144144 assert(x == 1);
145145}
146
147test "optional types" {
148 comptime {
149 const opt_type_struct = StructWithOptionalType { .t=u8, };
150 assert(opt_type_struct.t != null and opt_type_struct.t.? == u8);
151 }
152}
153
154const StructWithOptionalType = struct {
155 t: ?type,
156};
test/cases/reflection.zig+1-1
......@@ -2,7 +2,7 @@ const assert = @import("std").debug.assert;
22const mem = @import("std").mem;
33const reflection = this;
44
5test "reflection: array, pointer, nullable, error union type child" {
5test "reflection: array, pointer, optional, error union type child" {
66 comptime {
77 assert(([10]u8).Child == u8);
88 assert((*u8).Child == u8);
test/cases/struct.zig+17
......@@ -421,3 +421,20 @@ const Expr = union(enum) {
421421fn alloc(comptime T: type) []T {
422422 return []T{};
423423}
424
425test "call method with mutable reference to struct with no fields" {
426 const S = struct {
427 fn doC(s: *const this) bool {
428 return true;
429 }
430 fn do(s: *this) bool {
431 return true;
432 }
433 };
434
435 var s = S{};
436 assert(S.doC(&s));
437 assert(s.doC());
438 assert(S.do(&s));
439 assert(s.do());
440}
test/cases/type_info.zig+32-15
......@@ -39,12 +39,28 @@ test "type info: pointer type info" {
3939fn testPointer() void {
4040 const u32_ptr_info = @typeInfo(*u32);
4141 assert(TypeId(u32_ptr_info) == TypeId.Pointer);
42 assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One);
4243 assert(u32_ptr_info.Pointer.is_const == false);
4344 assert(u32_ptr_info.Pointer.is_volatile == false);
44 assert(u32_ptr_info.Pointer.alignment == 4);
45 assert(u32_ptr_info.Pointer.alignment == @alignOf(u32));
4546 assert(u32_ptr_info.Pointer.child == u32);
4647}
4748
49test "type info: unknown length pointer type info" {
50 testUnknownLenPtr();
51 comptime testUnknownLenPtr();
52}
53
54fn testUnknownLenPtr() void {
55 const u32_ptr_info = @typeInfo([*]const volatile f64);
56 assert(TypeId(u32_ptr_info) == TypeId.Pointer);
57 assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
58 assert(u32_ptr_info.Pointer.is_const == true);
59 assert(u32_ptr_info.Pointer.is_volatile == true);
60 assert(u32_ptr_info.Pointer.alignment == @alignOf(f64));
61 assert(u32_ptr_info.Pointer.child == f64);
62}
63
4864test "type info: slice type info" {
4965 testSlice();
5066 comptime testSlice();
......@@ -52,11 +68,12 @@ test "type info: slice type info" {
5268
5369fn testSlice() void {
5470 const u32_slice_info = @typeInfo([]u32);
55 assert(TypeId(u32_slice_info) == TypeId.Slice);
56 assert(u32_slice_info.Slice.is_const == false);
57 assert(u32_slice_info.Slice.is_volatile == false);
58 assert(u32_slice_info.Slice.alignment == 4);
59 assert(u32_slice_info.Slice.child == u32);
71 assert(TypeId(u32_slice_info) == TypeId.Pointer);
72 assert(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice);
73 assert(u32_slice_info.Pointer.is_const == false);
74 assert(u32_slice_info.Pointer.is_volatile == false);
75 assert(u32_slice_info.Pointer.alignment == 4);
76 assert(u32_slice_info.Pointer.child == u32);
6077}
6178
6279test "type info: array type info" {
......@@ -71,15 +88,15 @@ fn testArray() void {
7188 assert(arr_info.Array.child == bool);
7289}
7390
74test "type info: nullable type info" {
75 testNullable();
76 comptime testNullable();
91test "type info: optional type info" {
92 testOptional();
93 comptime testOptional();
7794}
7895
79fn testNullable() void {
96fn testOptional() void {
8097 const null_info = @typeInfo(?void);
81 assert(TypeId(null_info) == TypeId.Nullable);
82 assert(null_info.Nullable.child == void);
98 assert(TypeId(null_info) == TypeId.Optional);
99 assert(null_info.Optional.child == void);
83100}
84101
85102test "type info: promise info" {
......@@ -149,11 +166,11 @@ fn testUnion() void {
149166 assert(TypeId(typeinfo_info) == TypeId.Union);
150167 assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
151168 assert(typeinfo_info.Union.tag_type == TypeId);
152 assert(typeinfo_info.Union.fields.len == 26);
169 assert(typeinfo_info.Union.fields.len == 25);
153170 assert(typeinfo_info.Union.fields[4].enum_field != null);
154 assert((??typeinfo_info.Union.fields[4].enum_field).value == 4);
171 assert(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
155172 assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
156 assert(typeinfo_info.Union.defs.len == 21);
173 assert(typeinfo_info.Union.defs.len == 20);
157174
158175 const TestNoTagUnion = union {
159176 Foo: void,
test/cases/while.zig+6-6
......@@ -81,7 +81,7 @@ test "while with else" {
8181 assert(got_else == 1);
8282}
8383
84test "while with nullable as condition" {
84test "while with optional as condition" {
8585 numbers_left = 10;
8686 var sum: i32 = 0;
8787 while (getNumberOrNull()) |value| {
......@@ -90,7 +90,7 @@ test "while with nullable as condition" {
9090 assert(sum == 45);
9191}
9292
93test "while with nullable as condition with else" {
93test "while with optional as condition with else" {
9494 numbers_left = 10;
9595 var sum: i32 = 0;
9696 var got_else: i32 = 0;
......@@ -132,7 +132,7 @@ fn getNumberOrNull() ?i32 {
132132 };
133133}
134134
135test "while on nullable with else result follow else prong" {
135test "while on optional with else result follow else prong" {
136136 const result = while (returnNull()) |value| {
137137 break value;
138138 } else
......@@ -140,8 +140,8 @@ test "while on nullable with else result follow else prong" {
140140 assert(result == 2);
141141}
142142
143test "while on nullable with else result follow break prong" {
144 const result = while (returnMaybe(10)) |value| {
143test "while on optional with else result follow break prong" {
144 const result = while (returnOptional(10)) |value| {
145145 break value;
146146 } else
147147 i32(2);
......@@ -210,7 +210,7 @@ fn testContinueOuter() void {
210210fn returnNull() ?i32 {
211211 return null;
212212}
213fn returnMaybe(x: i32) ?i32 {
213fn returnOptional(x: i32) ?i32 {
214214 return x;
215215}
216216fn returnError() error!i32 {
test/compare_output.zig+2-2
......@@ -284,7 +284,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
284284 cases.addC("expose function pointer to C land",
285285 \\const c = @cImport(@cInclude("stdlib.h"));
286286 \\
287 \\export fn compare_fn(a: ?[*]const c_void, b: ?[*]const c_void) c_int {
287 \\export fn compare_fn(a: ?*const c_void, b: ?*const c_void) c_int {
288288 \\ const a_int = @ptrCast(*const i32, @alignCast(@alignOf(i32), a));
289289 \\ const b_int = @ptrCast(*const i32, @alignCast(@alignOf(i32), b));
290290 \\ if (a_int.* < b_int.*) {
......@@ -299,7 +299,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
299299 \\export fn main() c_int {
300300 \\ var array = []u32{ 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };
301301 \\
302 \\ c.qsort(@ptrCast(?[*]c_void, array[0..].ptr), c_ulong(array.len), @sizeOf(i32), compare_fn);
302 \\ c.qsort(@ptrCast(?*c_void, array[0..].ptr), c_ulong(array.len), @sizeOf(i32), compare_fn);
303303 \\
304304 \\ for (array) |item, i| {
305305 \\ if (item != i) {
test/compile_errors.zig+61-10
......@@ -1,6 +1,57 @@
11const tests = @import("tests.zig");
22
33pub fn addCases(cases: *tests.CompileErrorContext) void {
4 cases.add(
5 "use implicit casts to assign null to non-nullable pointer",
6 \\export fn entry() void {
7 \\ var x: i32 = 1234;
8 \\ var p: *i32 = &x;
9 \\ var pp: *?*i32 = &p;
10 \\ pp.* = null;
11 \\ var y = p.*;
12 \\}
13 ,
14 ".tmp_source.zig:4:23: error: expected type '*?*i32', found '**i32'",
15 );
16
17 cases.add(
18 "attempted implicit cast from T to [*]const T",
19 \\export fn entry() void {
20 \\ const x: [*]const bool = true;
21 \\}
22 ,
23 ".tmp_source.zig:2:30: error: expected type '[*]const bool', found 'bool'",
24 );
25
26 cases.add(
27 "dereference unknown length pointer",
28 \\export fn entry(x: [*]i32) i32 {
29 \\ return x.*;
30 \\}
31 ,
32 ".tmp_source.zig:2:13: error: index syntax required for unknown-length pointer type '[*]i32'",
33 );
34
35 cases.add(
36 "field access of unknown length pointer",
37 \\const Foo = extern struct {
38 \\ a: i32,
39 \\};
40 \\
41 \\export fn entry(foo: [*]Foo) void {
42 \\ foo.a += 1;
43 \\}
44 ,
45 ".tmp_source.zig:6:8: error: type '[*]Foo' does not support field access",
46 );
47
48 cases.add(
49 "unknown length pointer to opaque",
50 \\export const T = [*]@OpaqueType();
51 ,
52 ".tmp_source.zig:1:18: error: unknown-length pointer to opaque",
53 );
54
455 cases.add(
556 "error when evaluating return type",
657 \\const Foo = struct {
......@@ -1303,7 +1354,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
13031354 \\ if (true) |x| { }
13041355 \\}
13051356 ,
1306 ".tmp_source.zig:2:9: error: expected nullable type, found 'bool'",
1357 ".tmp_source.zig:2:9: error: expected optional type, found 'bool'",
13071358 );
13081359
13091360 cases.add(
......@@ -1742,7 +1793,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17421793 );
17431794
17441795 cases.add(
1745 "assign null to non-nullable pointer",
1796 "assign null to non-optional pointer",
17461797 \\const a: *u8 = null;
17471798 \\
17481799 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
......@@ -2258,7 +2309,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
22582309 \\
22592310 \\ defer try canFail();
22602311 \\
2261 \\ const a = maybeInt() ?? return;
2312 \\ const a = maybeInt() orelse return;
22622313 \\}
22632314 \\
22642315 \\fn canFail() error!void { }
......@@ -2779,7 +2830,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
27792830 );
27802831
27812832 cases.add(
2782 "while expected bool, got nullable",
2833 "while expected bool, got optional",
27832834 \\export fn foo() void {
27842835 \\ while (bar()) {}
27852836 \\}
......@@ -2799,23 +2850,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
27992850 );
28002851
28012852 cases.add(
2802 "while expected nullable, got bool",
2853 "while expected optional, got bool",
28032854 \\export fn foo() void {
28042855 \\ while (bar()) |x| {}
28052856 \\}
28062857 \\fn bar() bool { return true; }
28072858 ,
2808 ".tmp_source.zig:2:15: error: expected nullable type, found 'bool'",
2859 ".tmp_source.zig:2:15: error: expected optional type, found 'bool'",
28092860 );
28102861
28112862 cases.add(
2812 "while expected nullable, got error union",
2863 "while expected optional, got error union",
28132864 \\export fn foo() void {
28142865 \\ while (bar()) |x| {}
28152866 \\}
28162867 \\fn bar() error!i32 { return 1; }
28172868 ,
2818 ".tmp_source.zig:2:15: error: expected nullable type, found 'error!i32'",
2869 ".tmp_source.zig:2:15: error: expected optional type, found 'error!i32'",
28192870 );
28202871
28212872 cases.add(
......@@ -2829,7 +2880,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
28292880 );
28302881
28312882 cases.add(
2832 "while expected error union, got nullable",
2883 "while expected error union, got optional",
28332884 \\export fn foo() void {
28342885 \\ while (bar()) |x| {} else |err| {}
28352886 \\}
......@@ -3291,7 +3342,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
32913342 ".tmp_source.zig:9:4: error: variable of type 'comptime_float' must be const or comptime",
32923343 ".tmp_source.zig:10:4: error: variable of type '(block)' must be const or comptime",
32933344 ".tmp_source.zig:11:4: error: variable of type '(null)' must be const or comptime",
3294 ".tmp_source.zig:12:4: error: variable of type 'Opaque' must be const or comptime",
3345 ".tmp_source.zig:12:4: error: variable of type 'Opaque' not allowed",
32953346 ".tmp_source.zig:13:4: error: variable of type 'type' must be const or comptime",
32963347 ".tmp_source.zig:14:4: error: variable of type '(namespace)' must be const or comptime",
32973348 ".tmp_source.zig:15:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
test/tests.zig+6-6
......@@ -282,8 +282,8 @@ pub const CompareOutputContext = struct {
282282 var stdout = Buffer.initNull(b.allocator);
283283 var stderr = Buffer.initNull(b.allocator);
284284
285 var stdout_file_in_stream = io.FileInStream.init(&??child.stdout);
286 var stderr_file_in_stream = io.FileInStream.init(&??child.stderr);
285 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
286 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
287287
288288 stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable;
289289 stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable;
......@@ -601,8 +601,8 @@ pub const CompileErrorContext = struct {
601601 var stdout_buf = Buffer.initNull(b.allocator);
602602 var stderr_buf = Buffer.initNull(b.allocator);
603603
604 var stdout_file_in_stream = io.FileInStream.init(&??child.stdout);
605 var stderr_file_in_stream = io.FileInStream.init(&??child.stderr);
604 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
605 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
606606
607607 stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
608608 stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;
......@@ -872,8 +872,8 @@ pub const TranslateCContext = struct {
872872 var stdout_buf = Buffer.initNull(b.allocator);
873873 var stderr_buf = Buffer.initNull(b.allocator);
874874
875 var stdout_file_in_stream = io.FileInStream.init(&??child.stdout);
876 var stderr_file_in_stream = io.FileInStream.init(&??child.stderr);
875 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
876 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
877877
878878 stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
879879 stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;
test/translate_c.zig+20-20
......@@ -99,7 +99,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
9999 cases.add("restrict -> noalias",
100100 \\void foo(void *restrict bar, void *restrict);
101101 ,
102 \\pub extern fn foo(noalias bar: ?[*]c_void, noalias arg1: ?[*]c_void) void;
102 \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void;
103103 );
104104
105105 cases.add("simple struct",
......@@ -172,7 +172,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
172172 ,
173173 \\pub const struct_Foo = @OpaqueType();
174174 ,
175 \\pub extern fn some_func(foo: ?[*]struct_Foo, x: c_int) ?[*]struct_Foo;
175 \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo;
176176 ,
177177 \\pub const Foo = struct_Foo;
178178 );
......@@ -233,7 +233,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
233233 ,
234234 \\pub const Foo = c_void;
235235 ,
236 \\pub extern fn fun(a: ?[*]Foo) Foo;
236 \\pub extern fn fun(a: ?*Foo) Foo;
237237 );
238238
239239 cases.add("generate inline func for #define global extern fn",
......@@ -246,13 +246,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
246246 \\pub extern var fn_ptr: ?extern fn() void;
247247 ,
248248 \\pub inline fn foo() void {
249 \\ return (??fn_ptr)();
249 \\ return fn_ptr.?();
250250 \\}
251251 ,
252252 \\pub extern var fn_ptr2: ?extern fn(c_int, f32) u8;
253253 ,
254254 \\pub inline fn bar(arg0: c_int, arg1: f32) u8 {
255 \\ return (??fn_ptr2)(arg0, arg1);
255 \\ return fn_ptr2.?(arg0, arg1);
256256 \\}
257257 );
258258
......@@ -505,7 +505,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
505505 \\ return 6;
506506 \\}
507507 ,
508 \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?[*]c_void) c_int {
508 \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
509509 \\ if ((a != 0) and (b != 0)) return 0;
510510 \\ if ((b != 0) and (c != null)) return 1;
511511 \\ if ((a != 0) and (c != null)) return 2;
......@@ -608,7 +608,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
608608 \\ field: c_int,
609609 \\};
610610 \\pub export fn read_field(foo: ?[*]struct_Foo) c_int {
611 \\ return (??foo).field;
611 \\ return foo.?.field;
612612 \\}
613613 );
614614
......@@ -653,8 +653,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
653653 \\ return x;
654654 \\}
655655 ,
656 \\pub export fn foo(x: ?[*]c_ushort) ?[*]c_void {
657 \\ return @ptrCast(?[*]c_void, x);
656 \\pub export fn foo(x: ?[*]c_ushort) ?*c_void {
657 \\ return @ptrCast(?*c_void, x);
658658 \\}
659659 );
660660
......@@ -969,11 +969,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
969969 \\pub export fn bar() void {
970970 \\ var f: ?extern fn() void = foo;
971971 \\ var b: ?extern fn() c_int = baz;
972 \\ (??f)();
973 \\ (??f)();
972 \\ f.?();
973 \\ f.?();
974974 \\ foo();
975 \\ _ = (??b)();
976 \\ _ = (??b)();
975 \\ _ = b.?();
976 \\ _ = b.?();
977977 \\ _ = baz();
978978 \\}
979979 );
......@@ -984,7 +984,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
984984 \\}
985985 ,
986986 \\pub export fn foo(x: ?[*]c_int) void {
987 \\ (??x).* = 1;
987 \\ x.?.* = 1;
988988 \\}
989989 );
990990
......@@ -1012,7 +1012,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
10121012 \\pub fn foo() c_int {
10131013 \\ var x: c_int = 1234;
10141014 \\ var ptr: ?[*]c_int = &x;
1015 \\ return (??ptr).*;
1015 \\ return ptr.?.*;
10161016 \\}
10171017 );
10181018
......@@ -1119,7 +1119,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
11191119 \\pub const glClearPFN = PFNGLCLEARPROC;
11201120 ,
11211121 \\pub inline fn glClearUnion(arg0: GLbitfield) void {
1122 \\ return (??glProcs.gl.Clear)(arg0);
1122 \\ return glProcs.gl.Clear.?(arg0);
11231123 \\}
11241124 ,
11251125 \\pub const OpenGLProcs = union_OpenGLProcs;
......@@ -1173,7 +1173,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
11731173 \\ return !c;
11741174 \\}
11751175 ,
1176 \\pub fn foo(a: c_int, b: f32, c: ?[*]c_void) c_int {
1176 \\pub fn foo(a: c_int, b: f32, c: ?*c_void) c_int {
11771177 \\ return !(a == 0);
11781178 \\ return !(a != 0);
11791179 \\ return !(b != 0);
......@@ -1231,7 +1231,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
12311231 \\ B,
12321232 \\ C,
12331233 \\};
1234 \\pub fn if_none_bool(a: c_int, b: f32, c: ?[*]c_void, d: enum_SomeEnum) c_int {
1234 \\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int {
12351235 \\ if (a != 0) return 0;
12361236 \\ if (b != 0) return 1;
12371237 \\ if (c != null) return 2;
......@@ -1248,7 +1248,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
12481248 \\ return 3;
12491249 \\}
12501250 ,
1251 \\pub fn while_none_bool(a: c_int, b: f32, c: ?[*]c_void) c_int {
1251 \\pub fn while_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
12521252 \\ while (a != 0) return 0;
12531253 \\ while (b != 0) return 1;
12541254 \\ while (c != null) return 2;
......@@ -1264,7 +1264,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
12641264 \\ return 3;
12651265 \\}
12661266 ,
1267 \\pub fn for_none_bool(a: c_int, b: f32, c: ?[*]c_void) c_int {
1267 \\pub fn for_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
12681268 \\ while (a != 0) return 0;
12691269 \\ while (b != 0) return 1;
12701270 \\ while (c != null) return 2;